public static CodeStatement CreateToTargetAssignmentMethod(
            TranslateAttribute attr,
            CodeParameterDeclarationExpression toTarget,
            PropertyInfo sourceProperty,
            CodeVariableReferenceExpression fromSourceVar,
            Func <Type, Type, TranslateAttribute> getTypesTranslateAttributeFn)
        {
            //model.Name = this.Name;
            var targetProperty    = attr.TargetType.GetProperty(sourceProperty.Name);
            var cantWriteToTarget = targetProperty.GetSetMethod() == null;

            if (cantWriteToTarget)
            {
                return(new CodeCommentStatement(string.Format("Skipping property 'model.{0}' because 'model.{1}' is read-only",
                                                              targetProperty.Name, sourceProperty.Name)));
            }
            var cantReadFromSource = sourceProperty.GetGetMethod() == null;

            if (cantReadFromSource)
            {
                return(new CodeCommentStatement(string.Format("Skipping property 'model.{0}' because 'this.{1}' is write-only",
                                                              targetProperty.Name, sourceProperty.Name)));
            }

            var areBothTheSameTypes = targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType);

            if (areBothTheSameTypes)
            {
                return(toTarget.Assign(sourceProperty.Name, fromSourceVar.RefProperty(sourceProperty.Name)));
            }

            //model.BillingAddress = this.BillingAddress.ToTarget();
            var sourcePropertyType       = sourceProperty.PropertyType;
            var targetPropertyType       = targetProperty.PropertyType;
            var sourceAttr               = getTypesTranslateAttributeFn(sourcePropertyType, targetPropertyType);
            var isSourceTranslatableAlso = sourceAttr != null;
            var useExtensionMethods      = attr is TranslateExtensionAttribute;

            if (isSourceTranslatableAlso)
            {
                var toTargetMethodName = sourceAttr.GetConvertToTargetMethodName();
                var method             = fromSourceVar.RefProperty(sourceProperty.Name).Call(toTargetMethodName);

                return(fromSourceVar.RefProperty(sourceProperty.Name).IfIsNotNull(
                           toTarget.Assign(sourceProperty.Name, method)
                           ));
            }

            var sourceIsGenericList = sourcePropertyType.IsGenericType && sourcePropertyType.GetGenericTypeDefinition() == typeof(List <>);
            var targetIsGenericList = targetPropertyType.IsGenericType && targetPropertyType.GetGenericTypeDefinition() == typeof(List <>);
            var bothAreGenericLists = sourceIsGenericList && targetIsGenericList;

            if (bothAreGenericLists)
            {
                //to.PhoneNumbers = from.PhoneNumbers.ToPhoneNumbers();
                var propertyListItemTypeAttr = getTypesTranslateAttributeFn(sourcePropertyType.GetGenericArguments()[0], targetPropertyType.GetGenericArguments()[0]);
                var sourceIsTranslatable     = propertyListItemTypeAttr != null;
                if (sourceIsTranslatable)
                {
                    var toTargetsMethodName = propertyListItemTypeAttr.GetConvertToTargetsMethodName();
                    var method = useExtensionMethods
                                                                ? fromSourceVar.RefProperty(sourceProperty.Name).Call(toTargetsMethodName)
                                                                : propertyListItemTypeAttr.SourceType.Call(toTargetsMethodName, sourceProperty.Name.ThisProperty());

                    return(toTarget.Assign(sourceProperty.Name, method));
                }
            }

            //model.Type = StringConverterUtils.Parse<Target.PhoneNumberType>(this.Type);
            var sourcePropertyIsStringAndTargetIsConvertible = sourceProperty.PropertyType == typeof(string) &&
                                                               StringConverterUtils.CanCreateFromString(targetProperty.PropertyType);

            if (sourcePropertyIsStringAndTargetIsConvertible)
            {
                //model.CardType = StringConverterUtils.Parse<CardType>(this.CardType);
                var methodResult = typeof(StringConverterUtils).CallGeneric(CONVERTER_PARSE_METHOD,
                                                                            new[] { targetProperty.PropertyType.GenericDefinition() },
                                                                            fromSourceVar.RefProperty(sourceProperty.Name));

                return(toTarget.Assign(sourceProperty.Name.ThisProperty(), methodResult));
            }

            // Converting 'System.Collections.Generic.List`1 PhoneNumbers' to 'System.Collections.Generic.List`1 PhoneNumbers' is unsupported
            return(new CodeCommentStatement(string.Format("Converting '{0}.{1} {2}' to '{3}.{4} {5}' is unsupported"
                                                          , sourceProperty.PropertyType.Namespace, sourceProperty.PropertyType.Name, sourceProperty.Name
                                                          , targetProperty.PropertyType.Namespace, targetProperty.PropertyType.Name, targetProperty.Name)));
        }