Example #1
0
        private void EnsureNoInvalidMappings(List <PropertyOrFieldInfo> properties, ProposedTypeMapping typeMapping)
        {
            properties.AddRange(typeMapping.IncompatibleMappings);

            foreach (var mapping in typeMapping.ProposedTypeMappings)
            {
                EnsureNoInvalidMappings(properties, mapping);
            }
        }
        private void BuildCollectionComplexTypeExpression(Expression sourceAccess, List<MemberBinding> memberBindings, ProposedTypeMapping complexMember)
        {
            if (complexMember.Ignored)
              {
            return;
              }

              var typeOfSourceEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(complexMember.SourceMember.PropertyOrFieldType);

              var genericSourceEnumerable = typeof(IEnumerable<>).MakeGenericType(typeOfSourceEnumerable);

              var typeOfDestEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(complexMember.DestinationMember.PropertyOrFieldType);

              var genericDestEnumerable = typeof(IEnumerable<>).MakeGenericType(typeOfSourceEnumerable);

              var selectMethod = GetSelectMethod().MakeGenericMethod(typeOfSourceEnumerable, typeOfDestEnumerable);

              var selectParam = Expression.Parameter(typeOfSourceEnumerable, "src");

              var bindings = new List<MemberBinding>();

              var memberInit = BuildProjectionExpression(selectParam, typeOfDestEnumerable, complexMember);

              var funcType = typeof(Func<,>).MakeGenericType(typeOfSourceEnumerable, typeOfDestEnumerable);

              var memberInitLambda = Expression.Lambda(funcType, memberInit, selectParam);

              var accessMember = Expression.MakeMemberAccess(sourceAccess, complexMember.SourceMember);

              var callSelect = Expression.Call(null, selectMethod, accessMember, memberInitLambda);

              Expression finalExpression;

              var conversionMethod = DetermineIEnumerableConversionMethod(complexMember.DestinationMember.PropertyOrFieldType, typeOfSourceEnumerable, typeOfDestEnumerable);

              if (conversionMethod != null)
              {
            finalExpression = Expression.Call(null, conversionMethod, callSelect);
              }
              else
              {
            finalExpression = callSelect;
              }

              var bindSourceToDest = Expression.Bind(complexMember.DestinationMember, finalExpression);
              memberBindings.Add(bindSourceToDest);

              //BuildComplexTypeExpression(selectParam, bindings, complexMember);
        }
        private MemberInitExpression BuildProjectionExpression(Expression sourceAccess, Type destinationType, ProposedTypeMapping proposedMap)
        {
            var memberBindings = new List<MemberBinding>();

              foreach (var member in proposedMap.ProposedMappings)
              {
            BuildMemberAssignmentExpressions(sourceAccess, memberBindings, member, proposedMap.CustomMapping);
              }

              foreach (var complexMember in proposedMap.ProposedTypeMappings)
              {
            if (complexMember.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexMember))
            {
              if (mapper.Options.Projection.MapCollectionMembers)
              {
            BuildCollectionComplexTypeExpression(sourceAccess, memberBindings, complexMember);
              }
            }
            else
            {
              BuildComplexTypeExpression(sourceAccess, memberBindings, complexMember);
            }
              }

              var initDestination = Expression.MemberInit(Expression.New(destinationType), memberBindings);

              return initDestination;
        }
        private void BuildNonCollectionComplexTypeMappingExpressions(ParameterExpression source, ParameterExpression destination, ProposedTypeMapping complexTypeMapping, List<Expression> expressions, List<ParameterExpression> newParams)
        {
            ParameterExpression complexSource = null, complexDest = null;

              complexSource = Expression.Parameter(complexTypeMapping.SourceMember.PropertyOrFieldType, GetParameterName(complexTypeMapping.SourceMember));

              complexDest = Expression.Parameter(complexTypeMapping.DestinationMember.PropertyOrFieldType, GetParameterName(complexTypeMapping.DestinationMember));

              newParams.Add(complexSource);
              newParams.Add(complexDest);

              var ifNotNullBlock = new List<Expression>();

              ifNotNullBlock.Add(Expression.Assign(complexSource, Expression.Property(source, complexTypeMapping.SourceMember.Name)));

              var newType = complexTypeMapping.DestinationMember.PropertyOrFieldType;

              ifNotNullBlock.Add(Expression.Assign(complexDest, Expression.New(newType)));

              BuildTypeMappingExpressions(complexSource, complexDest, complexTypeMapping, ifNotNullBlock, newParams);

              ifNotNullBlock.Add(Expression.Assign(Expression.PropertyOrField(destination, complexTypeMapping.DestinationMember.Name), complexDest));

              Expression equalToNull = null;

              if (!complexTypeMapping.SourceMember.PropertyOrFieldType.IsValueType)
              {
            equalToNull = Expression.NotEqual(Expression.Property(source, complexTypeMapping.SourceMember.Name), Expression.Constant(null));
              }
              else
              {
            equalToNull = Expression.Constant(true);
              }

              var ifNotNullCheck = Expression.IfThen(equalToNull, Expression.Block(ifNotNullBlock));

              expressions.Add(ifNotNullCheck);
        }
Example #5
0
 public bool Equals(ProposedTypeMapping mapping)
 {
     return(this.DestinationMember == mapping.DestinationMember && this.SourceMember == mapping.SourceMember);
 }
Example #6
0
        private MemberInitExpression BuildProjectionExpression(Expression sourceAccess, Type destinationType, ProposedTypeMapping proposedMap)
        {
            var memberBindings = new List <MemberBinding>();

            foreach (var member in proposedMap.ProposedMappings)
            {
                BuildMemberAssignmentExpressions(sourceAccess, memberBindings, member, proposedMap.CustomMapping);
            }

            foreach (var complexMember in proposedMap.ProposedTypeMappings)
            {
                if (complexMember.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexMember))
                {
                    if (mapper.Options.Projection.MapCollectionMembers)
                    {
                        BuildCollectionComplexTypeExpression(sourceAccess, memberBindings, complexMember);
                    }
                }
                else
                {
                    BuildComplexTypeExpression(sourceAccess, memberBindings, complexMember);
                }
            }

            var initDestination = Expression.MemberInit(Expression.New(destinationType), memberBindings);

            return(initDestination);
        }
        /// <summary>
        /// Assign source member to a destination mapping, applying any custom mappings in the process.
        /// </summary>
        private void BuildMemberAssignmentExpressions(
      ParameterExpression source,
      ParameterExpression destination,
      ProposedMemberMapping member,
      List<Expression> expressions,
      ProposedTypeMapping typeMapping,
      CustomMapping customMapping = null
    )
        {
            if (member.Ignored)
              {
            return;
              }

              Expression condition = null;

              if (member.Condition != null)
              {
            mapProcessor.ParametersToReplace.Add(new ExpressionTuple(member.Condition.Parameters.Single(), this.sourceParameter));

            condition = member.Condition.Body;
              }

              var destMember = Expression.MakeMemberAccess(destination, member.DestinationMember);

              Expression assignSourceToDest = null;

              Expression customExpression = null;

              Expression assignConversionToDest = null;

              LambdaExpression conversionFunction = null;

              bool conversionReturnTypeSameAsParameterType = false;

              ParameterExpression conversionParameter = null;

              if (customMapping != null)
              {
            conversionFunction = customMapping.GetConversionFunction(member.SourceMember, member.DestinationMember);

            if (conversionFunction != null)
            {
              conversionParameter = conversionFunction.Parameters.Single();

              conversionReturnTypeSameAsParameterType = conversionParameter.Type == conversionFunction.ReturnType;
            }
              }

              if (customMapping != null && (customExpression = customMapping.GetExpressionForMember(member.DestinationMember)) != null)
              {
            assignSourceToDest = Expression.Assign(destMember, customExpression);
              }
              else if (member.HierarchicalMapping != null)
              {
            var accessHierarchy = BuildHierarchicalExpression(source, member.HierarchicalMapping, null);

            if (destMember.Type.IsNullableValueType())
            {
              accessHierarchy = Expression.Convert(accessHierarchy, destMember.Type);
            }

            assignSourceToDest = Expression.Assign(destMember, accessHierarchy);
              }
              else
              {
            Expression sourceExpression = Expression.MakeMemberAccess(source, member.SourceMember);

            bool usesConversionFunction = false;

            if (conversionFunction != null && !conversionReturnTypeSameAsParameterType)
            {
              ValidateConversionFunction(conversionFunction, conversionParameter, sourceExpression, destMember);

              this.mapProcessor.ParametersToReplace.Add(new ExpressionTuple(conversionParameter, sourceExpression));

              sourceExpression = conversionFunction.Body;
              usesConversionFunction = true;
            }

            assignSourceToDest = AssignSimpleProperty(member, destMember, sourceExpression, typeMapping, usesConversionFunction);
              }

              if (conversionFunction != null && conversionReturnTypeSameAsParameterType)
              {
            this.mapProcessor.ParametersToReplace.Add(new ExpressionTuple(conversionParameter, destMember));

            assignConversionToDest = Expression.Assign(destMember, conversionFunction.Body);
              }

              // If a condition to the mapping was specified
              if (condition != null)
              {
            if (assignConversionToDest != null)
            {
              assignSourceToDest = Expression.Block(assignSourceToDest, assignConversionToDest);
            }

            var ifCondition = Expression.IfThen(condition, assignSourceToDest);
            expressions.Add(ifCondition);
              }
              else
              {
            expressions.Add(assignSourceToDest);
            if (assignConversionToDest != null)
            {
              expressions.Add(assignConversionToDest);
            }
              }
        }
            private void GenerateEnumerableMapping(int currentDepth, MemberOptions options, CustomMapping customMapping, ProposedTypeMapping typeMapping, PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember)
            {
                var typeOfSourceEnumerable      = CollectionTypeHelper.GetTypeInsideEnumerable(sourceMember.PropertyOrFieldType);
                var typeOfDestinationEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(destinationMember.PropertyOrFieldType);

                var canAssignSourceItemsToDestination = CanAssignSourceItemsToDestination(destinationMember, sourceMember, typeOfSourceEnumerable, typeOfDestinationEnumerable);

                if (canAssignSourceItemsToDestination)
                {
                    typeMapping.ProposedTypeMappings.Add(
                        new ProposedTypeMapping
                    {
                        DestinationMember = destinationMember,
                        SourceMember      = sourceMember,
                        ProposedMappings  = new List <ProposedMemberMapping>()
                    });
                }
                else
                {
                    var complexPair = new TypePair(typeOfSourceEnumerable, typeOfDestinationEnumerable);

                    var complexTypeMapping = GetComplexTypeMapping(currentDepth + 1, complexPair, options, customMapping);

                    if (complexTypeMapping != null)
                    {
                        complexTypeMapping = complexTypeMapping.Clone();

                        complexTypeMapping.DestinationMember = destinationMember;
                        complexTypeMapping.SourceMember      = sourceMember;

                        CustomMapping customMappingForType;

                        TryGetCustomMapping(complexPair, out customMappingForType);

                        complexTypeMapping.CustomMapping = customMappingForType;

                        typeMapping.ProposedTypeMappings.Add(complexTypeMapping);
                    }
                    else
                    {
                        typeMapping.DoNotCache = true;
                    }
                }
            }
        private void BuildComplexTypeMappingExpressions(
      ParameterExpression source,
      ParameterExpression destination,
      ProposedTypeMapping complexTypeMapping,
      List<Expression> expressions)
        {
            if (complexTypeMapping.Ignored)
              {
            return;
              }

              ParameterExpression complexSource = null, complexDest = null;

              complexSource = ObtainParameter(complexTypeMapping.SourceMember.PropertyOrFieldType, GetParameterName(complexTypeMapping.SourceMember));

              complexDest = ObtainParameter(complexTypeMapping.DestinationMember.PropertyOrFieldType, GetParameterName(complexTypeMapping.DestinationMember));

              //newParameters.Add(complexSource);
              //newParameters.Add(complexDest);

              var ifNotNullBlock = new List<Expression>();

              ifNotNullBlock.Add(Expression.Assign(complexSource, Expression.MakeMemberAccess(source, complexTypeMapping.SourceMember)));

              ProcessTypeModifierData(complexSource, ifNotNullBlock, MappingSides.Source);

              var newType = complexTypeMapping.DestinationMember.PropertyOrFieldType;

              var accessDestinationMember = Expression.MakeMemberAccess(destination, complexTypeMapping.DestinationMember);

              if (TypeReceivesSpecialTreatment(newType))
              {
            ifNotNullBlock.Add
            (
              Expression.Assign
              (
            accessDestinationMember,
            HandleSpecialType
            (
              complexTypeMapping.SourceMember.PropertyOrFieldType,
              newType,
              complexSource
            )
              )
            );
              }
              else
              {
            // var destinationType = new DestinationType();
            Expression assignDestType;

            var destinationMemberCtor = GetConstructorForType(newType, this.sourceParameter, this.destinationParameter);

            if (options.Conventions.ReuseNonNullComplexMembersOnDestination)
            {
              var checkIfDestMemberIsNotNull = Expression.NotEqual(accessDestinationMember, Expression.Default(complexTypeMapping.DestinationMember.PropertyOrFieldType));

              assignDestType = Expression.Assign(complexDest,
            Expression.Condition(checkIfDestMemberIsNotNull,
              accessDestinationMember,
              destinationMemberCtor));
            }
            else
            {
              assignDestType = Expression.Assign(complexDest, destinationMemberCtor);

            }

            ifNotNullBlock.Add(assignDestType);

            BuildTypeMappingExpressions(complexSource, complexDest, complexTypeMapping, ifNotNullBlock, complexTypeMapping.CustomMapping);

            // destination.Member = destinationType;
            ifNotNullBlock.Add(Expression.Assign(Expression.MakeMemberAccess(destination, complexTypeMapping.DestinationMember), complexDest));
              }

              Expression condition;

              // If it's a value type, then a null check is not necessary, simply make it a
              // if(true) which will get eliminated by the JIT compiler.
              if (!complexTypeMapping.SourceMember.PropertyOrFieldType.IsValueType || options.Conventions.IgnoreMembersWithNullValueOnSource)
              {
            condition = Expression.NotEqual(Expression.MakeMemberAccess(source, complexTypeMapping.SourceMember), Expression.Default(complexTypeMapping.SourceMember.PropertyOrFieldType));
              }
              else
              {
            condition = Expression.Constant(true);
              }

              if (complexTypeMapping.Condition != null)
              {
            mapProcessor.ParametersToReplace.Add(new ExpressionTuple(complexTypeMapping.Condition.Parameters.Single(), this.sourceParameter));

            condition = Expression.AndAlso(condition, complexTypeMapping.Condition.Body);

              }

              var ifNotNullCheck = Expression.IfThen(condition, Expression.Block(ifNotNullBlock));

              expressions.Add(ifNotNullCheck);

              ReleaseParameter(complexSource);
              ReleaseParameter(complexDest);
        }
        /// <summary>
        /// Generates the loop that maps any IEnumerable type
        /// </summary>
        private void BuildEnumerableMappingExpressions(
      ParameterExpression source,
      ParameterExpression destination,
      ProposedTypeMapping complexTypeMapping,
      List<Expression> expressions
    )
        {
            // Find out the properties of this mapping which we will use to generate code
              var facts = FindEnumerableMappingFacts(source, destination, complexTypeMapping);

              // Early return because we're ignoring this mapping
              if (complexTypeMapping.Ignored)
              {
            return;
              }

              var ifNotNullBlock = new List<Expression>();

              Type destinationCollectionType;
              ParameterExpression destinationCollection;

              // If SourceMember is null, it means that the root type that is being mapped is enumerable itself.
              var accessSourceCollection = complexTypeMapping.SourceMember != null ?
            (Expression)Expression.MakeMemberAccess(source, complexTypeMapping.SourceMember) : source;

              var accessSourceEnumerableSize = GetEnumerableSizeAccessor(facts, accessSourceCollection);

              // destination.Collection = newCollection OR return destination, if destination is enumerable itself
              Expression accessDestinationCollection = complexTypeMapping.DestinationMember != null
            ? (Expression)Expression.MakeMemberAccess(destination, complexTypeMapping.DestinationMember)
            : destination;

              if (facts.CanAssignSourceToDestination && !facts.PreserveDestinationContents && !this.IsClone)
              {
            var assignSourceToDest = Expression.Assign(accessDestinationCollection, accessSourceCollection);
            expressions.Add(assignSourceToDest);
            return; // Early exit, nothing else to do but this simple assignment
              }

              // If it's an array, create a new array destination type
              if (facts.DestinationIsArray)
              {
            destinationCollectionType = facts.DestinationEnumerableType;

            //destinationCollection = Expression.Parameter(destinationCollectionType, GetCollectionName());

            destinationCollection = ObtainParameter(destinationCollectionType);

            //newParameters.Add(destinationCollection);

            var createDestinationCollection = Expression.New(destinationCollectionType.GetConstructors().Single(), accessSourceEnumerableSize);

            // destination = new DestinationType[source.Length/Count/Count()]
            var assignNewCollectionToDestination = Expression.Assign(destinationCollection, createDestinationCollection);

            ifNotNullBlock.Add(assignNewCollectionToDestination);
              }
              else
              {
            // if it's not a Dictionary type, use List as the container to create
            if (!facts.DestinationIsDictionaryType)
            {
              destinationCollectionType = typeof(List<>).MakeGenericType(facts.DestinationElementType);
            }
            else
            {
              destinationCollectionType = facts.DestinationEnumerableType;
            }

            Expression assignListTypeToParameter;

            var createDestinationCollection = Expression.New(destinationCollectionType);

            // If it's an IList but not an array we want to check if the destination property isn't null
            // and if it isn't, we want to reuse it.
            if (facts.PreserveDestinationContents)
            {
              Expression reuseCondition;

              if (facts.DestinationCouldBeArray && options.Safety.EnsureCollectionIsNotArrayType)
              {
            reuseCondition = Expression.And(Expression.NotEqual(accessDestinationCollection, Expression.Constant(null)),
              Expression.IsFalse(Expression.TypeIs(accessDestinationCollection, facts.DestinationElementType.MakeArrayType())));
              }
              else
              {
            reuseCondition = Expression.NotEqual(accessDestinationCollection, Expression.Constant(null));
              }

              assignListTypeToParameter = Expression.Condition(reuseCondition,
            accessDestinationCollection,
            Expression.Convert(createDestinationCollection, accessDestinationCollection.Type));

              destinationCollection = ObtainParameter(accessDestinationCollection.Type);
            }
            else
            {
              assignListTypeToParameter = createDestinationCollection;
              destinationCollection = ObtainParameter(destinationCollectionType);
            }

            // destination = new List<DestinationType>();
            var assignNewCollectionToDestination = Expression.Assign(destinationCollection, assignListTypeToParameter);

            ifNotNullBlock.Add(assignNewCollectionToDestination);
              }

              ParameterExpression sourceCollectionItem, destinationCollectionItem;

              if (facts.CanAssignSourceElementsToDestination
            && facts.SourceIsDictionaryType
            && facts.DestinationIsDictionaryType)
              {
            // If both types are a dictionary type and they are assignable to each other,
            // then we want to use the KeyValuePair itself, not just the value.
            sourceCollectionItem = ObtainParameter(facts.SourceElementType, "item");
            destinationCollectionItem = ObtainParameter(facts.DestinationElementType, "item");
              }
              else
              {

            if (facts.CanAssignSourceElementsToDestination && facts.SourceIsDictionaryType)
            {
              // Get the value type of the KeyValuePair
              sourceCollectionItem = ObtainParameter(facts.SourceElementType.GetGenericArguments().Last(), "item");
            }
            else
            {
              sourceCollectionItem = ObtainParameter(facts.SourceElementType, "item");
            }

            if (facts.CanAssignSourceElementsToDestination && facts.DestinationIsDictionaryType)
            {
              // Get the value type of the KeyValuePair
              destinationCollectionItem = ObtainParameter(facts.DestinationElementType.GetGenericArguments().Last(), "item");
            }
            else
            {
              destinationCollectionItem = ObtainParameter(facts.DestinationElementType, "item");
            }
              }

              var expressionsInsideLoop = new List<Expression>();

              BinaryExpression assignNewItemToDestinationItem;

              // The elements in the collection are not of types that are assignable to eachother
              // so we have to create a new item and do additional mapping (most likely).
              if (!facts.CanAssignSourceElementsToDestination)
              {
            var createNewDestinationCollectionItem = GetConstructorForType(facts.DestinationElementType, this.sourceParameter, this.destinationParameter);
            // var destinationItem = new DestinationItem();
            assignNewItemToDestinationItem = Expression.Assign(destinationCollectionItem, createNewDestinationCollectionItem);

            // Used as a flag by the member assignments of this type mapping if we do need to care
            // about preserving existing values on the destination, which we dont if the destination is a new instance
            complexTypeMapping.NewInstanceCreated = true;
              }
              else
              {
            // var destinationItem = sourceItem;
            assignNewItemToDestinationItem = Expression.Assign(destinationCollectionItem, sourceCollectionItem);

            // Used as a flag by the member assignments of this type mapping if we do need to care
            // about preserving existing values on the destination, which we do if the destination is not a new instance
            complexTypeMapping.NewInstanceCreated = false;
              }

              var @break = Expression.Label();

              var iteratorVar = ObtainParameter(typeof(int)); //Expression.Parameter(typeof(int), GetIteratorVarName());

              // i++
              var increment = Expression.PostIncrementAssign(iteratorVar);

              Expression assignItemToDestination;

              if (facts.DestinationIsArray)
              {
            // destination[i]
            var accessDestinationCollectionByIndex = Expression.MakeIndex(destinationCollection, null, new[] { iteratorVar });
            // destination[i] = destinationItem;
            var assignDestinationItemToArray = Expression.Assign(accessDestinationCollectionByIndex, destinationCollectionItem);

            assignItemToDestination = assignDestinationItemToArray;
              }
              else
              {
            var addMethod = typeof(ICollection<>).MakeGenericType(facts.DestinationElementType).GetMethod("Add", new[] { facts.DestinationElementType });

            var callAddOnDestinationCollection = Expression.Call(destinationCollection, addMethod, destinationCollectionItem);

            // destination.Add(destinationItem);
            assignItemToDestination = callAddOnDestinationCollection;

              }

              var loopBlock = new List<Expression>();

              // If it's an IList, we want to iterate through it using a good old for-loop for maximum efficiency.
              if (facts.SourceIsList)
              {
            // var i = 0
            var assignZeroToIteratorVar = Expression.Assign(iteratorVar, Expression.Constant(0));

            ifNotNullBlock.Add(assignZeroToIteratorVar);

            // i < source.Length/Count
            var terminationCondition = Expression.LessThan(iteratorVar, accessSourceEnumerableSize);

            // Find the first indexer property on the list type
            var indexer = facts.SourceEnumerableType.GetProperties().FirstOrDefault(p => p.GetIndexParameters().Length == 1);

            // source[i]
            Expression accessSourceCollectionByIndex = Expression.MakeIndex(accessSourceCollection, indexer, new[] { iteratorVar });

            if (facts.SourceIsDictionaryType)
            {
              accessSourceCollectionByIndex = Expression.Property(accessSourceCollectionByIndex, "Value");
            }

            // var item = source[i]
            var assignCurrent = Expression.Assign(sourceCollectionItem, accessSourceCollectionByIndex);

            expressionsInsideLoop.Add(assignCurrent);

            expressionsInsideLoop.Add(assignNewItemToDestinationItem);

            ProcessTypeModifierData(sourceCollectionItem, expressionsInsideLoop, MappingSides.Source);

            BuildTypeMappingExpressions(sourceCollectionItem, destinationCollectionItem, complexTypeMapping, expressionsInsideLoop, complexTypeMapping.CustomMapping);

            expressionsInsideLoop.Add(assignItemToDestination);

            expressionsInsideLoop.Add(increment);

            var blockInsideLoop = Expression.Block(expressionsInsideLoop);

            // i = 0; while(i < source.Length/Count) { .. i++; }
            var @for = Expression.Loop(
                        Expression.IfThenElse(
                        terminationCondition,
                            blockInsideLoop
                        , Expression.Break(@break)), @break);

            //ifNotNullBlock.Add(@for);
            loopBlock.Add(@for);
              }
              else // If it's any normal IEnumerable, use this faux foreach loop
              {
            var getEnumeratorOnSourceMethod = typeof(IEnumerable<>).MakeGenericType(facts.SourceElementType).GetMethod("GetEnumerator", Type.EmptyTypes);

            var sourceEnumeratorType = getEnumeratorOnSourceMethod.ReturnType;

            var sourceEnumerator = ObtainParameter(sourceEnumeratorType);

            var doMoveNextCall = Expression.Call(sourceEnumerator, typeof(IEnumerator).GetMethod("MoveNext"));

            var assignToEnum = Expression.Assign(sourceEnumerator, Expression.Call(accessSourceCollection, getEnumeratorOnSourceMethod));

            loopBlock.Add(assignToEnum);

            var accessCurrentOnEnumerator = Expression.Property(sourceEnumerator, "Current");

            if (facts.SourceIsDictionaryType && !facts.DestinationIsDictionaryType)
            {
              accessCurrentOnEnumerator = Expression.Property(accessCurrentOnEnumerator, "Value");
            }

            var assignCurrent = Expression.Assign(sourceCollectionItem, accessCurrentOnEnumerator);

            expressionsInsideLoop.Add(assignCurrent);
            expressionsInsideLoop.Add(assignNewItemToDestinationItem);

            ProcessTypeModifierData(sourceCollectionItem, expressionsInsideLoop, MappingSides.Source);

            BuildTypeMappingExpressions(sourceCollectionItem, destinationCollectionItem, complexTypeMapping, expressionsInsideLoop, complexTypeMapping.CustomMapping);

            expressionsInsideLoop.Add(assignItemToDestination);

            if (facts.DestinationIsArray)
            {
              expressionsInsideLoop.Add(increment);
            }

            var blockInsideLoop = Expression.Block(expressionsInsideLoop);

            // var enumerator = source.GetEnumerator();
            // while(enumerator.MoveNext()) { sourceItem = enumerator.Current; .. }
            var @foreach = Expression.Loop(
                        Expression.IfThenElse(
                        Expression.NotEqual(doMoveNextCall, Expression.Constant(false)),
                            blockInsideLoop
                        , Expression.Break(@break)), @break);

            //ifNotNullBlock.Add(@foreach);
            loopBlock.Add(@foreach);

            ReleaseParameter(sourceEnumerator);

              }

              var assignDestinationCollection = Expression.Assign(accessDestinationCollection, destinationCollection);

              //ifNotNullBlock.Add(assignDestinationCollection);
              loopBlock.Add(assignDestinationCollection);

              Expression sourceNotNullCondition = Expression.NotEqual(accessSourceCollection, Expression.Constant(null));

              if (complexTypeMapping.Condition != null)
              {
            mapProcessor.ParametersToReplace.Add(new ExpressionTuple(complexTypeMapping.Condition.Parameters.Single(), this.sourceParameter));

            sourceNotNullCondition = Expression.AndAlso(sourceNotNullCondition, complexTypeMapping.Condition.Body);
              }

              Expression ifEmptyCondition = null;

              Expression ifEmpty = null;

              if (facts.CanAssignSourceToDestination && facts.PreserveDestinationContents)
              {
            //var anyMethod = typeof(Enumerable).GetMethod("Any", new[] { typeof(IEnumerable<>) });

            var callAny = Expression.Call(null, anyMethod.MakeGenericMethod(facts.DestinationElementType), destinationCollection);

            var callReferenceEquals = Expression.Call(null, referenceEqualsMethod, accessSourceCollection, accessDestinationCollection);

            ifEmptyCondition = Expression.And(callAny, Expression.Not(callReferenceEquals));

            ifEmpty = Expression.Assign(accessDestinationCollection, accessSourceCollection);
              }
              else
              {
            ifEmptyCondition = Expression.Constant(true);
            ifEmpty = Expression.Empty();
              }

              var ifEmptyCheck = Expression.IfThenElse(ifEmptyCondition, Expression.Block(loopBlock), ifEmpty);

              ifNotNullBlock.Add(ifEmptyCheck);

              var ifNotNullCheck = Expression.IfThen(sourceNotNullCondition, Expression.Block(ifNotNullBlock));

              expressions.Add(ifNotNullCheck);

              ReleaseParameter(iteratorVar);

              ReleaseParameter(destinationCollection);

              ReleaseParameter(sourceCollectionItem);

              ReleaseParameter(destinationCollectionItem);
        }
        /// <summary>
        /// Assigns an expression that can be pretty much anything to a destination mapping.
        /// </summary>
        /// <returns></returns>
        private BinaryExpression AssignSimpleProperty(
      ProposedMemberMapping member,
      MemberExpression destination,
      Expression source,
      ProposedTypeMapping typeMapping,
      bool usesConversionFunction
    )
        {
            // If the destination is nullable but the source expression returns a non-nullable value type.
              if (destination.Type.IsNullableValueType() && !source.Type.IsNullableValueType())
              {
            source = HandleDestinationNullableValueType(destination, source);
              }
              // If the destination is not a nullable value type but the source expression does return one.
              else if (!destination.Type.IsNullableValueType() && source.Type.IsNullableValueType())
              {
            source = HandleSourceNullableValueType(destination, source);
              }
              // dest.Member = source.Member != null ? source.Member : dest.Member
              else if (source.Type.IsClass && options.Conventions.MakeCloneIfDestinationIsTheSameAsSource
            && source.Type.IsAssignableFrom(destination.Type)
            && !typeMapping.NewInstanceCreated
            && !usesConversionFunction)
              {
            source = Expression.Condition(Expression.NotEqual(source, Expression.Constant(null)), source, destination);
              }
              else if (destination.Type.IsNullableValueType() && source.Type.IsNullableValueType())
              {
            source = HandleNullableValueTypes(destination, source);
              }

              if (!source.Type.IsAssignableFrom(destination.Type))
              {
            // cast
            source = Expression.Convert(source, destination.Type);
              }

              return Expression.Assign(destination, source);
        }
        private EnumerableMappingFacts FindEnumerableMappingFacts(
      ParameterExpression source,
      ParameterExpression destination,
      ProposedTypeMapping complexTypeMapping)
        {
            var facts = new EnumerableMappingFacts();

              if (complexTypeMapping.SourceMember != null)
              {
            facts.SourceEnumerableType = complexTypeMapping.SourceMember.PropertyOrFieldType;
              }
              else
              {
            facts.SourceEnumerableType = source.Type;
              }

              if (complexTypeMapping.DestinationMember != null)
              {
            facts.DestinationEnumerableType = complexTypeMapping.DestinationMember.PropertyOrFieldType;
              }
              else
              {
            facts.DestinationEnumerableType = destination.Type;
              }

              facts.DestinationElementType = CollectionTypeHelper.GetTypeInsideEnumerable(facts.DestinationEnumerableType);

              facts.SourceElementType = CollectionTypeHelper.GetTypeInsideEnumerable(facts.SourceEnumerableType);

              facts.CanAssignSourceElementsToDestination = CanAssignSourceElementToDestination(complexTypeMapping, facts.DestinationElementType, facts.SourceElementType);

              // If we're working with a Dictionary as the source
              if (facts.SourceElementType.IsGenericType
            && typeof(KeyValuePair<,>).IsAssignableFrom(facts.SourceElementType.GetGenericTypeDefinition()))
              {
            facts.SourceIsDictionaryType = true;
              }

              // If we're working with a Dictionary as the destination
              if (facts.DestinationElementType.IsGenericType
            && typeof(KeyValuePair<,>).IsAssignableFrom(facts.DestinationElementType.GetGenericTypeDefinition()))
              {
            facts.DestinationIsDictionaryType = true;
              }

              facts.SourceIsArray = facts.SourceEnumerableType.IsArray;

              var genericCollection = typeof(ICollection<>).MakeGenericType(facts.SourceElementType);

              if (genericCollection.IsAssignableFrom(facts.SourceEnumerableType))
              {
            facts.SourceIsCollection = true;
              }
              else
              {
            facts.SourceIsIEnumerable = true;
              }

              facts.DestinationIsArray = facts.DestinationEnumerableType.IsArray;

              if (options.Conventions.PreserveDestinationListContents
              && IsCollectionType(facts.DestinationEnumerableType)
              && !facts.DestinationIsArray)
              {
            facts.PreserveDestinationContents = true;
              }

              if (IsListType(facts.SourceEnumerableType))
              {
            facts.SourceIsList = true;
              }

              if (facts.DestinationEnumerableType.IsAssignableFrom(facts.SourceEnumerableType))
              {
            facts.CanAssignSourceToDestination = true;
              }

              if (facts.DestinationEnumerableType.IsInterface)
              {
            facts.DestinationCouldBeArray = !facts.DestinationIsDictionaryType;
              }
              else if (facts.DestinationIsArray)
              {
            facts.DestinationCouldBeArray = true;
              }

              return facts;
        }
        private void BuildTypeMappingExpressions(ParameterExpression source, ParameterExpression destination, ProposedTypeMapping typeMapping, List<Expression> expressions, List<ParameterExpression> newParams, CustomMapping customMapping = null)
        {
            foreach (var member in typeMapping.ProposedMappings)
              {
            BuildSimpleTypeMappingExpressions(source, destination, member, expressions, newParams, customMapping);
              }

              foreach (var complexTypeMapping in typeMapping.ProposedTypeMappings)
              {
            if (typeMapping.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexTypeMapping))
            {
              BuildCollectionComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions, newParams);
            }
            else
            {
              BuildNonCollectionComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions, newParams);
            }
              }
        }
            /// <summary>
            /// Returns a type mapping of the TypePair you pass in.
            /// </summary>
            /// <returns></returns>
            private ProposedTypeMapping GetTypeMapping(int currentDepth, TypePair pair, MemberOptions options = null, CustomMapping customMapping = null)
            {
                if (!typeStack.Contains(pair))
                {
                    typeStack.Push(pair);
                }
                else if (this.options.Safety.IfRecursiveRelationshipIsDetected == RecursivePropertyOptions.ThrowIfRecursionIsDetected)
                {
                    // Oh noes, recursion!
                    throw new RecursiveRelationshipException(pair);
                }
                // if it's a recursive relationship, by default we return null which is handled after the method returns
                else
                {
                    return(null);
                }

                var typeMapping = new ProposedTypeMapping();

                typeMapping.SourceMember      = null;
                typeMapping.DestinationMember = null;

                Type destinationType, sourceType;

                // If it's an enumerable type (List<>, IEnumerable<>, etc) then we're currently interested
                // in the type 'inside' the enumerable.
                if (CollectionTypeHelper.IsEnumerable(pair.DestinationType))
                {
                    destinationType = CollectionTypeHelper.GetTypeInsideEnumerable(pair.DestinationType);
                }
                else
                {
                    destinationType = pair.DestinationType;
                }

                // Same here.
                if (CollectionTypeHelper.IsEnumerable(pair.SourceType))
                {
                    sourceType = CollectionTypeHelper.GetTypeInsideEnumerable(pair.SourceType);
                }
                else
                {
                    sourceType = pair.SourceType;
                }

                // The memberprovider is responsible for linking a destination member with a source member
                var memberProvider = this.strategy.MemberProviderFactory.GetMemberProvider(sourceType, destinationType, mapper);

                // Loop through all members it could find
                foreach (var mapping in GetTypeMembers(memberProvider, options, currentDepth))
                {
                    var destinationMember = mapping.Destination;
                    var sourceMember      = mapping.Source;

                    // Does the memberprovider see any reason to ignore this member?
                    if (memberProvider.IsMemberIgnored(sourceType, destinationMember))
                    {
                        continue;
                    }


                    Expression customExpression = null;

                    // Try to extract an expression that was supplied for this destination member
                    if (customMapping != null)
                    {
                        customExpression = customMapping.GetExpressionForMember(destinationMember);

                        if (mapping.ConversionFunction == null)
                        {
                            var conversionFunction = customMapping.GetConversionFunction(sourceMember, destinationMember);

                            mapping.ConversionFunction = conversionFunction;
                        }
                    }


                    // Did the user supply a function to transform the source member's value?
                    if (mapping.ConversionFunction != null)
                    {
                        // If no custom mapping yet, then we need to create one
                        // as it's where we'll be storing the conversion function
                        if (customMapping == null)
                        {
                            customMapping = new CustomMapping
                            {
                                DestinationType = destinationType
                            };

                            customMappingCache.AddOrUpdate(pair, customMapping, (k, v) => customMapping);

                            typeMapping.CustomMapping = customMapping;
                        }

                        // Let the custom mapping be the owner of the conversion function
                        customMapping.AddConversionFunction(sourceMember, destinationMember, mapping.ConversionFunction);
                    }
                    else if (customMapping != null)
                    {
                    }

                    ProposedHierarchicalMapping hierarchicalMapping = null;

                    // No source member or can't write to the destination?
                    if (HasNoSourceMember(customExpression, sourceMember) || !destinationMember.CanWrite)
                    {
                        if (this.options.Conventions.AutomaticallyFlattenHierarchies)
                        {
                            // Propose a mapping that flattens a hierarchy if possible.
                            // For example, map type.CompanyName to otherType.Company.Name
                            hierarchicalMapping = memberProvider.ProposeHierarchicalMapping(destinationMember);
                        }

                        // No way to map this thing? Add it to incompatible members if the option has been turned on.
                        // Will cause an (intended) exception later on, allowing you to verify your mappings
                        // for correctness and completeness.
                        if (hierarchicalMapping == null && this.options.Strictness.ThrowWithoutCorrespondingSourceMember)
                        {
                            typeMapping.IncompatibleMappings.Add(destinationMember);
                        }
                    }

                    // Nullable value types screw up everything!
                    var nullableType = NullableTypeHelper.TryGetNullableType(sourceMember);

                    // Can we do a simple right to left assignment between the members?
                    // So, are they basically the same type or do we need to do further mapping?
                    var canUseSimpleTypeMapping = CanUseDirectAssignment(pair, destinationMember, sourceMember, nullableType, hierarchicalMapping);

                    if (canUseSimpleTypeMapping)
                    {
                        // If simple mapping is possible create a mapping between the members
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember        = sourceMember,
                            DestinationMember   = destinationMember,
                            HierarchicalMapping = hierarchicalMapping
                        }
                        );
                    }
                    // No simple assignment, but a custom expression is supplied
                    // and that's just as good as having a direct assignment mapping
                    else if (customExpression != null || mapping.ConversionFunction != null)
                    {
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember        = sourceMember,
                            DestinationMember   = destinationMember,
                            HierarchicalMapping = hierarchicalMapping
                        }
                        );
                    }
                    // We have a source member but can't directly assign the source to the destination.
                    // Further mapping is needed.
                    else if (sourceMember != null)
                    {
                        // Is the member of an IEnumerable type?
                        if (AreMembersIEnumerable(destinationMember, sourceMember))
                        {
                            // Create a deeper mapping for IEnumerable members
                            GenerateEnumerableMapping(currentDepth, options, customMapping, typeMapping, destinationMember, sourceMember);
                        }
                        else
                        {
                            // Create a deeper mapping for a 'regular' type.
                            GenerateComplexTypeMapping(currentDepth, options, customMapping, typeMapping, destinationMember, sourceMember);
                        }
                    }
                    // All we have is a destination member and a custom expression
                    // that gives the destination member a value. Good enough!
                    else if (customExpression != null)
                    {
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember      = null,
                            DestinationMember = destinationMember
                        }
                        );
                    }
                }

                // Don't cache the typemapping when this flag has been set.
                // That happens when the maximum depth was reached during the mapping
                // for this particular type and we didn't explore the full depth
                // of the type. We don't wanna reuse this typemapping at a later time
                // because the mapping might be for something completely different
                // at a depth at which the full depth CAN be explored.
                if (!typeMapping.DoNotCache)
                {
                    mappingCache[pair] = typeMapping;
                }

                typeStack.Pop();

                return(typeMapping);
            }
        /// <summary>
        /// Processes a mapping for a type.
        /// </summary>
        private void BuildTypeMappingExpressions(
      ParameterExpression source,
      ParameterExpression destination,
      ProposedTypeMapping typeMapping,
      List<Expression> expressions,
      CustomMapping customMapping = null
    )
        {
            // If there's custom mapping defined
              if (customMapping != null)
              {
            // Custom mapping has a source parameter that needs to be replaced with actual parameter
            mapProcessor.ParametersToReplace.Add(new ExpressionTuple(customMapping.SourceParameter, source));

            // Custom mapping may contain more parameters that represent arguments in the custom mapping
            foreach (var param in customMapping.ArgumentParameters)
            {
              // Find the corresponding parameter that we want to replace the custom mapping's placeholder with
              var correspondingParam = this.Parameters.Single(p => p.Index == param.Index);
              mapProcessor.ParametersToReplace.Add(new ExpressionTuple(param.Parameter, correspondingParam.Parameter));
            }
              }

              // Simple property assignments
              foreach (var member in typeMapping.ProposedMappings)
              {
            BuildMemberAssignmentExpressions(source, destination, member, expressions, typeMapping, customMapping);
              }

              // Nested type mappings
              foreach (var complexTypeMapping in typeMapping.ProposedTypeMappings)
              {
            // If it's a collection type
            if (typeMapping.IsEnumerable || CollectionTypeHelper.IsEnumerable(complexTypeMapping))
            {
              BuildEnumerableMappingExpressions(source, destination, complexTypeMapping, expressions);
            }
            else
            {
              // If it's not a collection but just a nested type
              BuildComplexTypeMappingExpressions(source, destination, complexTypeMapping, expressions);
            }
              }
        }
            /// <summary>
            /// Go one deeper into the type hierarchy to map between a source and destination member.
            /// </summary>
            private void GenerateComplexTypeMapping(int currentDepth, MemberOptions options, CustomMapping customMapping, ProposedTypeMapping typeMapping, PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember)
            {
                var complexPair = new TypePair(sourceMember.PropertyOrFieldType, destinationMember.PropertyOrFieldType);

                // Go one deeper
                var complexTypeMapping = GetComplexTypeMapping(currentDepth + 1, complexPair, options, customMapping);

                // If a mapping has been found
                if (complexTypeMapping != null)
                {
                    complexTypeMapping = complexTypeMapping.Clone();

                    complexTypeMapping.DestinationMember = destinationMember;
                    complexTypeMapping.SourceMember      = sourceMember;

                    CustomMapping customMappingForType;

                    TryGetCustomMapping(complexPair, out customMappingForType);

                    complexTypeMapping.CustomMapping = customMappingForType;

                    typeMapping.ProposedTypeMappings.Add(complexTypeMapping);
                }
                else
                {
                    // If no mapping has been found, don't cache the 'owning' typemapping as it will cause issues later
                    typeMapping.DoNotCache = true;
                }
            }
        private bool CanAssignSourceElementToDestination(ProposedTypeMapping complexTypeMapping, Type destinationCollectionElementType, Type sourceCollectionElementType)
        {
            var canAssignSourceElementToDest = destinationCollectionElementType.IsAssignableFrom(sourceCollectionElementType);

              if (canAssignSourceElementToDest)
              {
            if (this.IsClone && !sourceCollectionElementType.IsPrimitive && sourceCollectionElementType != typeof(string))
            {
              return false;
            }
              }
              else if (sourceCollectionElementType.IsGenericType
            && typeof(KeyValuePair<,>).IsAssignableFrom(sourceCollectionElementType.GetGenericTypeDefinition()))
              {
            return CanAssignSourceElementToDestination(complexTypeMapping, destinationCollectionElementType, sourceCollectionElementType.GetGenericArguments().Last());
              }

              return canAssignSourceElementToDest;
        }
Example #18
0
        private void BuildComplexTypeExpression(Expression sourceAccess, List <MemberBinding> memberBindings, ProposedTypeMapping complexMember)
        {
            Expression accessMember = Expression.MakeMemberAccess(sourceAccess, complexMember.SourceMember);

            var type = complexMember.DestinationMember.PropertyOrFieldType;

            var memberInit = BuildProjectionExpression(accessMember, type, complexMember);

            var bindSourceToDest = Expression.Bind(complexMember.DestinationMember, memberInit);

            memberBindings.Add(bindSourceToDest);
        }
 public static bool IsEnumerable(ProposedTypeMapping mapping)
 {
     return typeof(IEnumerable).IsAssignableFrom(mapping.SourceMember.PropertyOrFieldType)
     && typeof(IEnumerable).IsAssignableFrom(mapping.DestinationMember.PropertyOrFieldType);
 }
Example #20
0
        private void BuildCollectionComplexTypeExpression(Expression sourceAccess, List <MemberBinding> memberBindings, ProposedTypeMapping complexMember)
        {
            if (complexMember.Ignored)
            {
                return;
            }

            var typeOfSourceEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(complexMember.SourceMember.PropertyOrFieldType);

            var genericSourceEnumerable = typeof(IEnumerable <>).MakeGenericType(typeOfSourceEnumerable);

            var typeOfDestEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(complexMember.DestinationMember.PropertyOrFieldType);

            var genericDestEnumerable = typeof(IEnumerable <>).MakeGenericType(typeOfSourceEnumerable);

            var selectMethod = GetSelectMethod().MakeGenericMethod(typeOfSourceEnumerable, typeOfDestEnumerable);

            var selectParam = Expression.Parameter(typeOfSourceEnumerable, "src");

            var bindings = new List <MemberBinding>();

            var memberInit = BuildProjectionExpression(selectParam, typeOfDestEnumerable, complexMember);

            var funcType = typeof(Func <,>).MakeGenericType(typeOfSourceEnumerable, typeOfDestEnumerable);

            var memberInitLambda = Expression.Lambda(funcType, memberInit, selectParam);

            var accessMember = Expression.MakeMemberAccess(sourceAccess, complexMember.SourceMember);

            var callSelect = Expression.Call(null, selectMethod, accessMember, memberInitLambda);

            Expression finalExpression;

            var conversionMethod = DetermineIEnumerableConversionMethod(complexMember.DestinationMember.PropertyOrFieldType, typeOfSourceEnumerable, typeOfDestEnumerable);

            if (conversionMethod != null)
            {
                finalExpression = Expression.Call(null, conversionMethod, callSelect);
            }
            else
            {
                finalExpression = callSelect;
            }


            var bindSourceToDest = Expression.Bind(complexMember.DestinationMember, finalExpression);

            memberBindings.Add(bindSourceToDest);

            //BuildComplexTypeExpression(selectParam, bindings, complexMember);
        }
 public bool Equals(ProposedTypeMapping mapping)
 {
     return this.DestinationMember == mapping.DestinationMember && this.SourceMember== mapping.SourceMember;
 }
Example #22
0
 public IncompatibleMapping(PropertyOrFieldInfo member, ProposedTypeMapping mapping = null)
 {
     this.mapping = mapping;
     this.member  = member;
 }
        private void BuildComplexTypeExpression(Expression sourceAccess, List<MemberBinding> memberBindings, ProposedTypeMapping complexMember)
        {
            Expression accessMember = Expression.MakeMemberAccess(sourceAccess, complexMember.SourceMember);

              var type = complexMember.DestinationMember.PropertyOrFieldType;

              var memberInit = BuildProjectionExpression(accessMember, type, complexMember);

              var bindSourceToDest = Expression.Bind(complexMember.DestinationMember, memberInit);
              memberBindings.Add(bindSourceToDest);
        }
Example #24
0
 public static bool IsEnumerable(ProposedTypeMapping mapping)
 {
     return(IsEnumerable(mapping.SourceMember.PropertyOrFieldType) &&
            IsEnumerable(mapping.DestinationMember.PropertyOrFieldType));
 }
        private void BuildCollectionComplexTypeMappingExpressions(ParameterExpression source, ParameterExpression destination, ProposedTypeMapping complexTypeMapping, List<Expression> expressions, List<ParameterExpression> newParams)
        {
            Type sourceMemberPropertyType, destinationMemberPropertyType;

              if (complexTypeMapping.SourceMember != null)
              {
            sourceMemberPropertyType = complexTypeMapping.SourceMember.PropertyOrFieldType;
              }
              else
              {
            sourceMemberPropertyType = source.Type;
              }

              if (complexTypeMapping.DestinationMember != null)
              {
            destinationMemberPropertyType = complexTypeMapping.DestinationMember.PropertyOrFieldType;
              }
              else
              {
            destinationMemberPropertyType = destination.Type;
              }

              var ifNotNullBlock = new List<Expression>();

              var destinationCollectionElementType = CollectionTypeHelper.GetTypeInsideEnumerable(destinationMemberPropertyType);

              var sourceCollectionElementType = CollectionTypeHelper.GetTypeInsideEnumerable(sourceMemberPropertyType);

              var sourceElementSameAsDestination = destinationCollectionElementType == sourceCollectionElementType;

              Type destinationCollectionType;
              ParameterExpression destinationCollection;

              Expression accessSourceCollection = complexTypeMapping.SourceMember != null ? (Expression)Expression.MakeMemberAccess(source, complexTypeMapping.SourceMember) : source;

              Expression accessSourceCollectionSize;

              if (sourceMemberPropertyType.IsArray)
              {
            accessSourceCollectionSize = Expression.Property(accessSourceCollection, "Length");
              }
              else
              {

            var genericCollection = typeof(ICollection<>).MakeGenericType(sourceCollectionElementType);

            if (genericCollection.IsAssignableFrom(sourceMemberPropertyType))
            {
              var countProperty = genericCollection.GetProperty("Count");

              accessSourceCollectionSize = Expression.Property(accessSourceCollection, countProperty);
            }
            else
            {

              var countMethod = (from m in typeof(Enumerable).GetMethods()
                             where m.Name == "Count" && m.IsGenericMethod
                             && m.GetParameters().Length == 1
                             select m).FirstOrDefault();

              var genericEnumerable = typeof(IEnumerable<>).MakeGenericType(sourceCollectionElementType);

              accessSourceCollectionSize = Expression.Call(null, countMethod.MakeGenericMethod(sourceCollectionElementType), accessSourceCollection);
            }
              }

              if (destinationMemberPropertyType.IsArray)
              {
            destinationCollectionType = destinationMemberPropertyType;

            destinationCollection = Expression.Parameter(destinationCollectionType, GetCollectionName());

            newParams.Add(destinationCollection);

            var createDestinationCollection = Expression.New(destinationCollectionType.GetConstructors().Single(), accessSourceCollectionSize);

            var assignNewCollectionToDestination = Expression.Assign(destinationCollection, createDestinationCollection);

            ifNotNullBlock.Add(assignNewCollectionToDestination);
              }
              else
              {
            destinationCollectionType = typeof(List<>).MakeGenericType(destinationCollectionElementType);

            var createDestinationCollection = Expression.New(destinationCollectionType);

            destinationCollection = Expression.Parameter(destinationCollectionType, GetCollectionName());

            newParams.Add(destinationCollection);

            var assignNewCollectionToDestination = Expression.Assign(destinationCollection, createDestinationCollection);

            ifNotNullBlock.Add(assignNewCollectionToDestination);
              }

              var sourceCollectionItem = Expression.Parameter(sourceCollectionElementType, GetCollectionElementName());

              var expressionsInsideLoop = new List<Expression>();

              var destinationCollectionItem = Expression.Parameter(destinationCollectionElementType, GetCollectionElementName());

              BinaryExpression assignNewItemToDestinationItem;

              if (!sourceElementSameAsDestination)
              {
            var createNewDestinationCollectionItem = Expression.New(destinationCollectionElementType);
            assignNewItemToDestinationItem = Expression.Assign(destinationCollectionItem, createNewDestinationCollectionItem);
              }
              else
              {
            assignNewItemToDestinationItem = Expression.Assign(destinationCollectionItem, sourceCollectionItem);
              }
              newParams.Add(sourceCollectionItem);
              newParams.Add(destinationCollectionItem);

              var @break = Expression.Label();

              var iteratorVar = Expression.Parameter(typeof(int), GetIteratorVarName());

              var increment = Expression.PostIncrementAssign(iteratorVar);

              Expression assignItemToDestination;

              if (destinationCollectionType.IsArray)
              {
            var accessDestinationCollectionByIndex = Expression.MakeIndex(destinationCollection, null, new[] { iteratorVar });

            var assignDestinationItemToArray = Expression.Assign(accessDestinationCollectionByIndex, destinationCollectionItem);

            assignItemToDestination = assignDestinationItemToArray;
              }
              else
              {
            var addMethod = destinationCollectionType.GetMethod("Add", new[] { destinationCollectionElementType });
            var callAddOnDestinationCollection = Expression.Call(destinationCollection, addMethod, destinationCollectionItem);

            assignItemToDestination = callAddOnDestinationCollection;

              }

              if (typeof(IList).IsAssignableFrom(sourceMemberPropertyType)
            || (sourceMemberPropertyType.IsGenericType && typeof(IList<>).IsAssignableFrom(sourceMemberPropertyType.GetGenericTypeDefinition())))
              {

            newParams.Add(iteratorVar);

            var assignZeroToIteratorVar = Expression.Assign(iteratorVar, Expression.Constant(0));

            ifNotNullBlock.Add(assignZeroToIteratorVar);

            var terminationCondition = Expression.LessThan(iteratorVar, accessSourceCollectionSize);

            var indexer = sourceMemberPropertyType.GetProperties().FirstOrDefault(p => p.GetIndexParameters().Length == 1);

            var accessSourceCollectionByIndex = Expression.MakeIndex(accessSourceCollection, indexer, new[] { iteratorVar });

            var assignCurrent = Expression.Assign(sourceCollectionItem, accessSourceCollectionByIndex);

            expressionsInsideLoop.Add(assignCurrent);

            expressionsInsideLoop.Add(assignNewItemToDestinationItem);

            BuildTypeMappingExpressions(sourceCollectionItem, destinationCollectionItem, complexTypeMapping, expressionsInsideLoop, newParams);

            expressionsInsideLoop.Add(assignItemToDestination);

            expressionsInsideLoop.Add(increment);

            var blockInsideLoop = Expression.Block(expressionsInsideLoop);

            var @foreach = Expression.Loop(
                        Expression.IfThenElse(
                        terminationCondition,
                            blockInsideLoop
                        , Expression.Break(@break)), @break);

            ifNotNullBlock.Add(@foreach);
              }
              else
              {

            var getEnumeratorOnSourceMethod = sourceMemberPropertyType.GetMethod("GetEnumerator", Type.EmptyTypes);

            var sourceEnumeratorType = getEnumeratorOnSourceMethod.ReturnType;

            var sourceEnumerator = Expression.Parameter(sourceEnumeratorType, GetEnumeratorName());

            if (destinationMemberPropertyType.IsArray)
            {
              newParams.Add(iteratorVar);
            }

            newParams.Add(sourceEnumerator);

            var doMoveNextCall = Expression.Call(sourceEnumerator, typeof(IEnumerator).GetMethod("MoveNext"));

            var assignToEnum = Expression.Assign(sourceEnumerator, Expression.Call(accessSourceCollection, getEnumeratorOnSourceMethod));

            ifNotNullBlock.Add(assignToEnum);

            var assignCurrent = Expression.Assign(sourceCollectionItem, Expression.Property(sourceEnumerator, "Current"));

            expressionsInsideLoop.Add(assignCurrent);
            expressionsInsideLoop.Add(assignNewItemToDestinationItem);

            BuildTypeMappingExpressions(sourceCollectionItem, destinationCollectionItem, complexTypeMapping, expressionsInsideLoop, newParams);

            expressionsInsideLoop.Add(assignItemToDestination);

            if (destinationMemberPropertyType.IsArray)
            {
              expressionsInsideLoop.Add(increment);
            }

            var blockInsideLoop = Expression.Block(expressionsInsideLoop);

            var @foreach = Expression.Loop(
                        Expression.IfThenElse(
                        Expression.NotEqual(doMoveNextCall, Expression.Constant(false)),
                            blockInsideLoop
                        , Expression.Break(@break)), @break);

            ifNotNullBlock.Add(@foreach);

              }

              Expression accessDestinationCollection = complexTypeMapping.DestinationMember != null ? (Expression) Expression.MakeMemberAccess(destination, complexTypeMapping.DestinationMember) : destination;

              var assignDestinationCollection = Expression.Assign(accessDestinationCollection, destinationCollection);

              ifNotNullBlock.Add(assignDestinationCollection);

              var ifNotNullCheck = Expression.IfThen(Expression.NotEqual(accessSourceCollection, Expression.Constant(null)), Expression.Block(ifNotNullBlock));

              expressions.Add(ifNotNullCheck);
        }