internal static Expression MapCollectionExpression(this TypeMapRegistry typeMapRegistry,
                                                           IConfigurationProvider configurationProvider, PropertyMap propertyMap, Expression sourceExpression,
                                                           Expression destExpression, Expression contextExpression, Func <Expression, Expression> conditionalExpression, Type ifInterfaceType, MapItem mapItem)
        {
            var passedDestination = Variable(destExpression.Type, "passedDestination");
            var condition         = conditionalExpression(passedDestination);
            var newExpression     = Variable(passedDestination.Type, "collectionDestination");
            var sourceElementType = TypeHelper.GetElementType(sourceExpression.Type);
            ParameterExpression itemParam;

            var itemExpr = mapItem(typeMapRegistry, configurationProvider, propertyMap, sourceExpression.Type, passedDestination.Type, contextExpression, out itemParam);

            var destinationElementType    = itemExpr.Type;
            var destinationCollectionType = typeof(ICollection <>).MakeGenericType(destinationElementType);

            if (!destinationCollectionType.IsAssignableFrom(destExpression.Type))
            {
                destinationCollectionType = typeof(IList);
            }
            var addMethod   = destinationCollectionType.GetDeclaredMethod("Add");
            var destination = propertyMap?.UseDestinationValue == true ? passedDestination : newExpression;
            var addItems    = ForEach(sourceExpression, itemParam, Call(destination, addMethod, itemExpr));

            var mapExpr = Block(addItems, destination);

            var allowNullCollections = propertyMap?.TypeMap.Profile.AllowNullCollections ??
                                       configurationProvider.Configuration.AllowNullCollections;
            var ifNullExpr  = allowNullCollections ? Constant(null, passedDestination.Type) : (Expression)newExpression;
            var clearMethod = destinationCollectionType.GetDeclaredMethod("Clear");
            var checkNull   =
                Block(new[] { newExpression, passedDestination },
                      Assign(passedDestination, destExpression),
                      IfThenElse(condition ?? Constant(false),
                                 Block(Assign(newExpression, passedDestination), Call(newExpression, clearMethod)),
                                 Assign(newExpression, passedDestination.Type.NewExpr(ifInterfaceType))),
                      Condition(Equal(sourceExpression, Constant(null)), ToType(ifNullExpr, passedDestination.Type), ToType(mapExpr, passedDestination.Type))
                      );

            if (propertyMap != null)
            {
                return(checkNull);
            }
            var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType);

            if (elementTypeMap == null)
            {
                return(checkNull);
            }
            var checkContext = TypeMapPlanBuilder.CheckContext(elementTypeMap, contextExpression);

            if (checkContext == null)
            {
                return(checkNull);
            }
            return(Block(checkContext, checkNull));
        }
Exemple #2
0
        internal static Expression MapCollectionExpression(this TypeMapRegistry typeMapRegistry,
                                                           IConfigurationProvider configurationProvider, PropertyMap propertyMap, Expression sourceExpression,
                                                           Expression destExpression, Expression contextExpression, Func <Expression, Expression> conditionalExpression, Type ifInterfaceType, MapItem mapItem)
        {
            var passedDestination = Expression.Variable(destExpression.Type, "passedDestination");
            var condition         = conditionalExpression(passedDestination);
            var newExpression     = Expression.Variable(passedDestination.Type, "collectionDestination");
            var sourceElementType = TypeHelper.GetElementType(sourceExpression.Type);
            var itemParam         = Expression.Parameter(sourceElementType, "item");

            var itemExpr = mapItem(typeMapRegistry, configurationProvider, propertyMap, sourceExpression.Type, passedDestination.Type, itemParam, contextExpression);

            var destinationElementType    = itemExpr.Type;
            var destinationCollectionType = typeof(ICollection <>).MakeGenericType(destinationElementType);
            var clearMethod   = destinationCollectionType.GetDeclaredMethod("Clear");
            var cast          = typeof(Enumerable).GetDeclaredMethod("Cast").MakeGenericMethod(itemParam.Type);
            var addMethod     = destinationCollectionType.GetDeclaredMethod("Add");
            var genericSource = sourceExpression.Type.IsGenericType() ? sourceExpression : Expression.Call(null, cast, sourceExpression);
            var destination   = propertyMap?.UseDestinationValue == true ? passedDestination : newExpression;
            var addItems      = ExpressionExtensions.ForEach(genericSource, itemParam, Expression.Call(destination, addMethod, itemExpr));

            var mapExpr = Expression.Block(addItems, destination);

            var ifNullExpr = configurationProvider.Configuration.AllowNullCollections ? Expression.Constant(null, passedDestination.Type) : (Expression)newExpression;
            var checkNull  =
                Expression.Block(new[] { newExpression, passedDestination },
                                 Expression.Assign(passedDestination, destExpression),
                                 Expression.IfThenElse(condition ?? Expression.Constant(false),
                                                       Expression.Block(Expression.Assign(newExpression, passedDestination), Expression.Call(newExpression, clearMethod)),
                                                       Expression.Assign(newExpression, passedDestination.Type.NewExpr(ifInterfaceType))),
                                 Expression.Condition(Expression.Equal(sourceExpression, Expression.Constant(null)), ExpressionExtensions.ToType(ifNullExpr, passedDestination.Type), ExpressionExtensions.ToType(mapExpr, passedDestination.Type))
                                 );

            if (propertyMap != null)
            {
                return(checkNull);
            }
            var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType);

            if (elementTypeMap == null)
            {
                return(checkNull);
            }
            var checkContext = TypeMapPlanBuilder.CheckContext(elementTypeMap, contextExpression);

            if (checkContext == null)
            {
                return(checkNull);
            }
            return(Expression.Block(checkContext, checkNull));
        }
        internal static Expression MapCollectionExpression(this TypeMapRegistry typeMapRegistry,
                                                           IConfigurationProvider configurationProvider, PropertyMap propertyMap, Expression sourceExpression,
                                                           Expression destExpression, Expression contextExpression, Func <Expression, Expression> conditionalExpression, Type ifInterfaceType, MapItem mapItem)
        {
            var passedDestination  = Variable(destExpression.Type, "passedDestination");
            var newExpressionValue = passedDestination.NewIfConditionFails(conditionalExpression, ifInterfaceType);
            var newExpression      = Variable(newExpressionValue.Type, "collectionDestination");
            var sourceElementType  = TypeHelper.GetElementType(sourceExpression.Type);
            var itemParam          = Parameter(sourceElementType, "item");
            var itemExpr           = mapItem(typeMapRegistry, configurationProvider, propertyMap, sourceExpression.Type, passedDestination.Type, itemParam, contextExpression);

            var blockExpressions = new List <Expression>();
            var blockVariables   = new List <ParameterExpression> {
                newExpression, passedDestination
            };
            Expression destination;
            var        destinationElementType    = itemExpr.Type;
            var        destinationCollectionType = typeof(ICollection <>).MakeGenericType(destinationElementType);
            var        clearMethod = destinationCollectionType.GetDeclaredMethod("Clear");

            if (passedDestination.Type.IsCollectionType())
            {
                if (propertyMap == null)
                {
                    destination = newExpression;
                    blockExpressions.Add(IfThenElse(NotEqual(passedDestination, Constant(null)),
                                                    Call(passedDestination, clearMethod),
                                                    Assign(destination, newExpression)
                                                    ));
                }
                else if (propertyMap.UseDestinationValue)
                {
                    destination = passedDestination;
                    blockExpressions.Add(Call(passedDestination, clearMethod));
                }
                else
                {
                    destination = newExpression;
                }
            }
            else
            {
                destination = newExpression;
            }

            var cast = typeof(Enumerable).GetTypeInfo().DeclaredMethods.First(_ => _.Name == "Cast").MakeGenericMethod(itemParam.Type);

            var addMethod     = destinationCollectionType.GetDeclaredMethod("Add");
            var genericSource = sourceExpression.Type.GetTypeInfo().IsGenericType ? sourceExpression : Call(null, cast, sourceExpression);

            blockExpressions.Add(ForEach(genericSource, itemParam, Call(
                                             destination,
                                             addMethod,
                                             itemExpr)));

            blockExpressions.Add(destination);

            var mapExpr = Block(blockExpressions);

            var ifNullExpr = configurationProvider.Configuration.AllowNullCollections ? Constant(null, passedDestination.Type) : (Expression)newExpression;
            var checkNull  = Block(blockVariables,
                                   Assign(passedDestination, destExpression),
                                   Assign(newExpression, newExpressionValue),
                                   Condition(Equal(sourceExpression, Constant(null)), ToType(ifNullExpr, passedDestination.Type), ToType(mapExpr, passedDestination.Type))
                                   );

            if (propertyMap != null)
            {
                return(checkNull);
            }
            var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType);

            if (elementTypeMap == null)
            {
                return(checkNull);
            }
            var checkContext = TypeMapPlanBuilder.CheckContext(elementTypeMap, contextExpression);

            if (checkContext == null)
            {
                return(checkNull);
            }
            return(Block(checkContext, checkNull));
        }