private void WriteCustomValidation(ILWriter writer, PropertyInfo property, CustomValidationAttribute customValidationAttribute)
        {
            var validationKind = ValidationKind.Custom;

            var validatorType = typeof(ICustomValidator <>).MakeGenericType(property.PropertyType);

            if (!customValidationAttribute.ValidatorType.CanBe(validatorType))
            {
                var message = CommonErrors.CustomValidatorMustBeOfType.WithValues(property.ReflectedType.Name, property.Name, property.PropertyType.Name);
                throw new IncorrectValidationAttributeException(typeof(CustomValidationAttribute), message);
            }

            var localValidator = writer.DeclareLocal(validatorType);

            writer.New(customValidationAttribute.ValidatorType);
            writer.SetLocal(localValidator);

            var validate = KnownMetadata.Methods.ICustomValidator_OfType(property.PropertyType);

            writer.LoadLocal(localValidator);
            writer.LoadFirstParameter();
            writer.GetPropertyValue(property);
            writer.InstanceMethodCall(validate);

            var end = writer.IfFalseThen();

            WriteFailureResult(writer, validationKind, CommonResults.CustomValidationDidNotSucceed.WithValues(property.ReflectedType.Name, property.Name));
            writer.Return();

            writer.MarkLabel(end);
        }
        void WriteTranslatorBody <TFrom, TTo>(ILWriter writer)
        {
            var sourceProperties         = typeof(TFrom).GetPublicPropertiesWithGetter();
            var targetProperties         = typeof(TTo).GetPublicPropertiesWithSetter().ToDictionary(p => p.Name);
            var targetedSourceProperties = sourceProperties.GetTranslatableProperties <TTo>();

            if (targetProperties.Count == 0)
            {
                writer.ReturnNull();
                return;
            }

            var localTargetInstance = writer.DeclareLocal <TTo>();

            writer.New <TTo>();
            writer.SetLocal(localTargetInstance);

            foreach (var sourceProperty in sourceProperties)
            {
                var explicitMapping = GetExplicitMappingIfPresent <TTo>(sourceProperty);

                var targetName = (explicitMapping == null) ? sourceProperty.Name : explicitMapping.PropertyName;

                if (!targetProperties.ContainsKey(targetName))
                {
                    if (this.shouldThrowExceptions)
                    {
                        throw new PropertyIsMissingException();
                    }
                    continue;
                }

                var targetProperty = targetProperties[targetName];

                var propertiesAreSameType = sourceProperty.PropertyType == targetProperty.PropertyType;

                if (!propertiesAreSameType && !sourceProperty.PropertyType.HasConversionTo(targetProperty.PropertyType))
                {
                    if (this.shouldThrowExceptions)
                    {
                        throw new PropertyTypeMismatchException();
                    }
                    continue;
                }

                var localSourceValue = writer.DeclareLocal(sourceProperty.PropertyType);

                writer.LoadFirstParameter();
                writer.GetPropertyValue(sourceProperty);
                writer.SetLocal(localSourceValue);

                writer.LoadLocal(localTargetInstance);
                writer.LoadLocal(localSourceValue);

                if (!propertiesAreSameType)
                {
                    writer.Cast(sourceProperty.PropertyType, targetProperty.PropertyType);
                }

                writer.SetPropertyValue(targetProperty);
            }

            writer.LoadLocal(localTargetInstance);
            writer.Return();
            writer.VerifyStack();
        }
        private void WriteLogBody(ILWriter writer, Type type, MemberInfo[] loggableMembers)
        {
            var localTypedInstance = writer.DeclareLocal(type);

            writer.LoadFirstParameter();
            writer.Cast(typeof(object), type);
            writer.SetLocal(localTypedInstance);

            //TODO: Recurse into loggable members
            foreach (var member in loggableMembers)
            {
                var logAttributes = member.GetCustomAttributes <LogAttribute>().ToArray();

                if (logAttributes.Length == 0)
                {
                    continue;
                }

                //TODO: Support multiple attributes per member
                var attribute = logAttributes[0];

                if (attribute.Ignore)
                {
                    continue;
                }

                if (CanWriteToLog(attribute.Visibility))
                {
                    LocalBuilder localValue;
                    LocalBuilder localLogItem = writer.DeclareLocal <CustomLoggableMember>();

                    switch (member.MemberType)
                    {
                    case MemberTypes.Field:
                        var field = (FieldInfo)member;
                        localValue = writer.DeclareLocal(field.FieldType);

                        writer.LoadLocal(localTypedInstance);
                        writer.LoadField(field);
                        writer.SetLocal(localValue);
                        break;

                    case MemberTypes.Property:
                        var property = (PropertyInfo)member;
                        localValue = writer.DeclareLocal(property.PropertyType);

                        writer.LoadLocal(localTypedInstance);
                        writer.GetPropertyValue(property);
                        writer.SetLocal(localValue);
                        break;

                    default:
                        var message = String.Format("Encountered loggable member '{0}' that was not supported in IL generation", member.Name);
                        System.Diagnostics.Debug.Fail(message);
                        throw new ILGenerationException(message);
                    }

                    writer.New <CustomLoggableMember>();
                    writer.SetLocal(localLogItem);

                    writer.LoadLocal(localLogItem);
                    writer.LoadInt32((int)attribute.Visibility);
                    writer.SetPropertyValue(typeof(CustomLoggableMember).GetProperty("MemberVisibility"));

                    writer.LoadLocal(localLogItem);
                    writer.TypeOf(type);
                    writer.Cast(localValue.LocalType, typeof(Type));
                    writer.SetPropertyValue(KnownMetadata.Properties.CustomLoggableMember_OwningType);

                    writer.LoadLocal(localLogItem);
                    writer.LoadString(member.Name);
                    writer.SetPropertyValue(KnownMetadata.Properties.CustomLoggableMember_MemberName);

                    writer.LoadLocal(localLogItem);
                    writer.TypeOf(localValue.LocalType);
                    writer.Cast(localValue.LocalType, typeof(Type));
                    writer.SetPropertyValue(KnownMetadata.Properties.CustomLoggableMember_MemberType);

                    writer.LoadLocal(localLogItem);
                    writer.LoadLocal(localValue);
                    writer.SetPropertyValue(KnownMetadata.Properties.CustomLoggableMember_MemberValue);

                    writer.LoadSecondParameter();
                    writer.LoadLocal(localLogItem);
                    writer.ActionDelegateMethodCall <CustomLoggableMember>();
                }
            }

            writer.Return();
        }