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)); }
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)); }