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); }
public bool Equals(ProposedTypeMapping mapping) { return(this.DestinationMember == mapping.DestinationMember && this.SourceMember == mapping.SourceMember); }
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; }
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); }
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; }
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); }
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); }