protected Expression GetMemberMappings(TypeMapping typeMapping) { var context = new ReferenceMapperContext(typeMapping.TypePair.SourceType, typeMapping.TypePair.TargetType, typeMapping); //since nested selectors are supported, we sort membermappings to grant //that we assign outer objects first var memberMappings = typeMapping.MemberMappings.Values.ToList(); if (typeMapping.IgnoreMemberMappingResolvedByConvention) { memberMappings = memberMappings.Where(mapping => mapping.MappingResolution != MappingResolution.RESOLVED_BY_CONVENTION).ToList(); } var memberMappingExps = memberMappings .Where(mapping => !mapping.Ignore) .Where(mapping => !mapping.SourceMember.Ignore) .Where(mapping => !mapping.TargetMember.Ignore) .OrderBy(mm => mm, _memberComparer) .Select(mapping => { if (mapping.Mapper is ReferenceMapper) { return(GetComplexMemberExpression(mapping)); } return(GetSimpleMemberExpression(mapping)); }).ToList(); return(!memberMappingExps.Any() ? (Expression)Expression.Empty() : Expression.Block(memberMappingExps)); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; var targetCollectionInsertionMethod = GetTargetCollectionInsertionMethod(context); if (context.IsSourceElementTypeBuiltIn || context.IsTargetElementTypeBuiltIn) { return(Expression.Block(SimpleCollectionLoop ( context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar ))); } return(Expression.Block(ComplexCollectionLoop ( context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.ReferenceTracker, context.Mapper ))); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; //1. Reverse the Stack by creating a new temporary Stack passing source as input //2. Read items from the newly created temporary stack and add items to the target var paramType = new Type[] { typeof(IEnumerable <>) .MakeGenericType(context.SourceCollectionElementType) }; var tempCollectionType = this.GetTemporaryCollectionType(context); var tempCollectionConstructorInfo = tempCollectionType.GetConstructor(paramType); var tempCollection = Expression.Parameter(tempCollectionType, "tempCollection"); var newTempCollectionExp = Expression.New(tempCollectionConstructorInfo, context.SourceInstance); if (context.IsTargetElementTypeBuiltIn) { return(Expression.Block ( new[] { tempCollection }, Expression.Assign(tempCollection, newTempCollectionExp), SimpleCollectionLoop(context, tempCollection, context.TargetInstance) )); } return(Expression.Block ( new[] { tempCollection }, Expression.Assign(tempCollection, newTempCollectionExp), CollectionLoopWithReferenceTracking(context, tempCollection, context.TargetInstance) )); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; /* By default I try to retrieve the item-insertion method of the collection. * The exact name of the method can be overridden so that, for example, * on Queue you search for 'Enqueue'. The default method name searched is 'Add'. * * If the item-insertion method does not exist, try to retrieve a constructor * which takes as its only parameter 'IEnumerable<T>'. If this constructor * exists a temporary List<T> is created and then passed to the constructor. * * If neither the item insertion method nor the above constructor exist * an exception is thrown */ /* -Typically a Costructor(IEnumerable<T>) is faster than AddRange that is faster than Add. * By the way Construcor( capacity ) + AddRange has roughly the same performance of Construcor( IEnumerable<T> ). */ bool isUpdateCollection = /*context.Options.ReferenceBehavior == ReferenceBehaviors.USE_TARGET_INSTANCE_IF_NOT_NULL &&*/ context.Options.CollectionBehavior == CollectionBehaviors.UPDATE; bool isMerge = /*context.Options.ReferenceBehavior == ReferenceBehaviors.USE_TARGET_INSTANCE_IF_NOT_NULL &&*/ context.Options.CollectionBehavior == CollectionBehaviors.MERGE; var targetCollectionInsertionMethod = GetTargetCollectionInsertionMethod(context); if (context.IsSourceElementTypeBuiltIn || context.IsTargetElementTypeBuiltIn || context.IsSourceElementTypeStruct || context.IsTargetElementTypeStruct) { return(Expression.Block ( isMerge ? Expression.Empty() : GetTargetCollectionClearExpression(context), SimpleCollectionLoop(context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar) )); } return(Expression.Block ( GetTargetCollectionClearExpression(context), isUpdateCollection ? GetUpdateCollectionExpression(context) : ComplexCollectionLoop(context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.ReferenceTracker, context.Mapper) )); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; /* By default I try to retrieve the item-insertion method of the collection. * The exact name of the method can be overridden so that, for example, * on Queue you search for 'Enqueue'. The default method name searched is 'Add'. * * If the item-insertion method does not exist, try to retrieve a constructor * which takes as its only parameter 'IEnumerable<T>'. If this constructor * exists a temporary List<T> is created and then passed to the constructor. * * If neither the item insertion method nor the above constructor exist * an exception is thrown */ /* -Typically a Costructor(IEnumerable<T>) is faster than AddRange that is faster than Add. * By the way Construcor( capacity ) + AddRange has roughly the same performance of Construcor( IEnumerable<T> ). */ var clearMethod = GetTargetCollectionClearMethod(context); if (clearMethod == null && context.Options.CollectionMappingStrategy == CollectionMappingStrategies.RESET) { string msg = $@"Cannot reset the collection. Type '{nameof( context.TargetInstance.Type )}' does not provide a Clear method"; throw new Exception(msg); } if (context.IsSourceElementTypeBuiltIn || context.IsTargetElementTypeBuiltIn) { return(Expression.Block ( context.Options.CollectionMappingStrategy == CollectionMappingStrategies.RESET ? Expression.Call(context.TargetInstance, clearMethod) : (Expression)Expression.Empty(), SimpleCollectionLoop(context, context.SourceInstance, context.TargetInstance) )); } return(Expression.Block ( context.Options.CollectionMappingStrategy == CollectionMappingStrategies.RESET ? Expression.Call(context.TargetInstance, clearMethod) : (Expression)Expression.Empty(), CollectionLoopWithReferenceTracking(context, context.SourceInstance, context.TargetInstance) )); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as DictionaryMapperContext; var addMethod = base.GetTargetCollectionInsertionMethod(context); var keyExpression = this.GetKeyOrValueExpression(context, context.SourceCollectionElementKey, context.TargetCollectionElementKey); var valueExpression = this.GetKeyOrValueExpression(context, context.SourceCollectionElementValue, context.TargetCollectionElementValue); return(Expression.Block ( new[] { context.Mapper, context.SourceCollectionElementKey, context.SourceCollectionElementValue, context.TargetCollectionElementKey, context.TargetCollectionElementValue }, Expression.Assign(context.Mapper, Expression.Constant(_mapper)), ExpressionLoops.ForEach(context.SourceInstance, context.SourceCollectionLoopingVar, Expression.Block ( Expression.Assign(context.SourceCollectionElementKey, Expression.Property(context.SourceCollectionLoopingVar, nameof(DictionaryEntry.Key))), Expression.Assign(context.SourceCollectionElementValue, Expression.Property(context.SourceCollectionLoopingVar, nameof(DictionaryEntry.Value))), keyExpression, valueExpression, Expression.Call(context.TargetInstance, addMethod, context.TargetCollectionElementKey, context.TargetCollectionElementValue) )) )); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; //1. Create a new temporary collection passing source as input //2. Read items from the newly created temporary collection and add items to the target var paramType = new Type[] { typeof(IEnumerable <>) .MakeGenericType(context.SourceCollectionElementType) }; var tempCollectionType = this.GetTemporaryCollectionType(context); var tempCollectionConstructorInfo = tempCollectionType.GetConstructor(paramType); var tempCollection = Expression.Parameter(tempCollectionType, "tempCollection"); var newTempCollectionExp = Expression.New(tempCollectionConstructorInfo, context.SourceInstance); var temporaryCollectionInsertionMethod = this.GetTargetCollectionInsertionMethod(context); bool isUpdate = context.Options.CollectionBehavior == CollectionBehaviors.UPDATE; bool isReset = context.Options.CollectionBehavior == CollectionBehaviors.RESET; if (context.IsTargetElementTypeBuiltIn) { return(Expression.Block ( new[] { tempCollection }, isReset ? GetTargetCollectionClearExpression(context) : Expression.Empty(), Expression.Assign(tempCollection, newTempCollectionExp), SimpleCollectionLoop ( tempCollection, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, temporaryCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.Mapper, context.ReferenceTracker ) )); } return(Expression.Block ( new[] { tempCollection }, Expression.Assign(tempCollection, newTempCollectionExp), isUpdate ? GetUpdateCollectionExpression(context) : ComplexCollectionLoop ( tempCollection, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, temporaryCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.ReferenceTracker, context.Mapper ) )); }
protected virtual Expression GetExpressionBody(ReferenceMapperContext contextObj) { return(Expression.Empty()); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { return(Expression.Empty()); }
protected override Expression GetExpressionBody(ReferenceMapperContext contextObj) { var context = contextObj as CollectionMapperContext; /* By default I try to retrieve the item-insertion method of the collection. * The exact name of the method can be overridden so that, for example, * on Queue you search for 'Enqueue'. The default method name searched is 'Add'. * * If the item-insertion method does not exist, try to retrieve a constructor * which takes as its only parameter 'IEnumerable<T>'. If this constructor * exists a temporary List<T> is created and then passed to the constructor. * * If neither the item insertion method nor the above constructor exist * an exception is thrown */ /* -Typically a Costructor(IEnumerable<T>) is faster than AddRange that is faster than Add. * By the way Construcor( capacity ) + AddRange has roughly the same performance of Construcor( IEnumerable<T> ). */ //reset only if we keep using the same target instance bool isResetCollection = context.Options.ReferenceBehavior != ReferenceBehaviors.CREATE_NEW_INSTANCE && context.Options.CollectionBehavior == CollectionBehaviors.RESET; bool isUpdateCollection = /*context.Options.ReferenceBehavior == ReferenceBehaviors.USE_TARGET_INSTANCE_IF_NOT_NULL &&*/ context.Options.CollectionBehavior == CollectionBehaviors.UPDATE; var targetCollectionInsertionMethod = GetTargetCollectionInsertionMethod(context); //if( context.SourceCollectionElementType.IsInterface ) //{ // throw new NotImplementedException( "collections of interface element type not fully supported yet" ); // //especially interface -> simple type //} if ((context.IsSourceElementTypeBuiltIn || context.IsTargetElementTypeBuiltIn || context.SourceCollectionElementType.IsValueType || context.TargetCollectionElementType.IsValueType)) { return(Expression.Block ( isResetCollection ? GetTargetCollectionClearExpression(context) : Expression.Empty(), SimpleCollectionLoop(context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.Mapper, context.ReferenceTracker) )); } return(Expression.Block ( isResetCollection ? GetTargetCollectionClearExpression(context) : Expression.Empty(), isUpdateCollection ? GetUpdateCollectionExpression(context) : ComplexCollectionLoop ( context.SourceInstance, context.SourceCollectionElementType, context.TargetInstance, context.TargetCollectionElementType, targetCollectionInsertionMethod, context.SourceCollectionLoopingVar, context.ReferenceTracker, context.Mapper, context ) )); }