public LambdaExpression CreateMapExpression(ExpressionRequest request, Internal.IDictionary <ExpressionRequest, int> typePairCount) { // this is the input parameter of this expression with name <variableName> var instanceParameter = Expression.Parameter(request.SourceType, "dto"); var total = CreateMapExpression(request, instanceParameter, typePairCount); var delegateType = typeof(Func <,>).MakeGenericType(request.SourceType, request.DestinationType); return(Expression.Lambda(delegateType, total, instanceParameter)); }
private static MemberAssignment BindEnumerableExpression(IMappingEngine mappingEngine, PropertyMap propertyMap, ExpressionRequest request, ExpressionResolutionResult result, Internal.IDictionary <ExpressionRequest, int> typePairCount) { MemberAssignment bindExpression; var destinationListType = GetDestinationListTypeFor(propertyMap); var sourceListType = result.Type.IsArray ? result.Type.GetElementType() : result.Type.GetGenericArguments().First(); var listTypePair = new ExpressionRequest(sourceListType, destinationListType, request.MembersToExpand); var selectExpression = result.ResolutionExpression; if (sourceListType != destinationListType) { var transformedExpression = ((IMappingEngineRunner)mappingEngine).CreateMapExpression(listTypePair, typePairCount); selectExpression = Expression.Call( typeof(Enumerable), "Select", new[] { sourceListType, destinationListType }, result.ResolutionExpression, transformedExpression); } if (typeof(IList <>).MakeGenericType(destinationListType) .IsAssignableFrom(propertyMap.DestinationPropertyType) || typeof(ICollection <>).MakeGenericType(destinationListType) .IsAssignableFrom(propertyMap.DestinationPropertyType)) { // Call .ToList() on IEnumerable var toListCallExpression = GetToListCallExpression(propertyMap, destinationListType, selectExpression); bindExpression = Expression.Bind(propertyMap.DestinationProperty.MemberInfo, toListCallExpression); } else if (propertyMap.DestinationPropertyType.IsArray) { // Call .ToArray() on IEnumerable var toArrayCallExpression = Expression.Call( typeof(Enumerable), "ToArray", new[] { destinationListType }, selectExpression); bindExpression = Expression.Bind(propertyMap.DestinationProperty.MemberInfo, toArrayCallExpression); } else { // destination type implements ienumerable, but is not an ilist. allow deferred enumeration bindExpression = Expression.Bind(propertyMap.DestinationProperty.MemberInfo, selectExpression); } return(bindExpression); }
public MappingEngine(IConfigurationProvider configurationProvider, Internal.IDictionary <TypePair, IObjectMapper> objectMapperCache, Internal.IDictionary <ExpressionRequest, LambdaExpression> expressionCache, Func <Type, object> serviceCtor) { ConfigurationProvider = configurationProvider; _objectMapperCache = objectMapperCache; _expressionCache = expressionCache; _serviceCtor = serviceCtor; _mappers = configurationProvider.GetMappers(); ConfigurationProvider.TypeMapCreated += ClearTypeMap; }
public Expression CreateMapExpression(ExpressionRequest request, Expression instanceParameter, Internal.IDictionary <ExpressionRequest, int> typePairCount) { var typeMap = ConfigurationProvider.ResolveTypeMap(request.SourceType, request.DestinationType); if (typeMap == null) { const string MessageFormat = "Missing map from {0} to {1}. Create using Mapper.CreateMap<{0}, {1}>."; var message = string.Format(MessageFormat, request.SourceType.Name, request.DestinationType.Name); throw new InvalidOperationException(message); } var parameterReplacer = instanceParameter is ParameterExpression ? new ParameterReplacementVisitor(instanceParameter) : null; var customProjection = typeMap.CustomProjection; if (customProjection != null) { return(parameterReplacer == null ? customProjection.Body : parameterReplacer.Visit(customProjection.Body)); } var bindings = CreateMemberBindings(request, typeMap, instanceParameter, typePairCount); Expression constructorExpression = typeMap.DestinationConstructorExpression(instanceParameter); if (parameterReplacer != null) { constructorExpression = parameterReplacer.Visit(constructorExpression); } var visitor = new NewFinderVisitor(); visitor.Visit(constructorExpression); var expression = Expression.MemberInit( visitor.NewExpression, bindings.ToArray() ); return(expression); }
private static MemberAssignment BindMappedTypeExpression(IMappingEngine mappingEngine, PropertyMap propertyMap, ExpressionRequest request, ExpressionResolutionResult result, Internal.IDictionary <ExpressionRequest, int> typePairCount) { var transformedExpression = Extensions.CreateMapExpression(mappingEngine, request, result.ResolutionExpression, typePairCount); // Handles null source property so it will not create an object with possible non-nullable propeerties // which would result in an exception. if (mappingEngine.ConfigurationProvider.MapNullSourceValuesAsNull) { var expressionNull = Expression.Constant(null, propertyMap.DestinationPropertyType); transformedExpression = Expression.Condition(Expression.NotEqual(result.ResolutionExpression, Expression.Constant(null)), transformedExpression, expressionNull); } return(Expression.Bind(propertyMap.DestinationProperty.MemberInfo, transformedExpression)); }
public MemberAssignment Build(IMappingEngine mappingEngine, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, Internal.IDictionary <ExpressionRequest, int> typePairCount) { return(BindMappedTypeExpression(mappingEngine, propertyMap, request, result, typePairCount)); }
private List <MemberBinding> CreateMemberBindings(ExpressionRequest request, TypeMap typeMap, Expression instanceParameter, Internal.IDictionary <ExpressionRequest, int> typePairCount) { var bindings = new List <MemberBinding>(); var visitCount = typePairCount.AddOrUpdate(request, 0, (tp, i) => i + 1); if (visitCount >= typeMap.MaxDepth) { return(bindings); } foreach (var propertyMap in typeMap.GetPropertyMaps().Where(pm => pm.CanResolveValue())) { var result = ResolveExpression(propertyMap, request.SourceType, instanceParameter); if (propertyMap.ExplicitExpansion && !request.MembersToExpand.Contains(propertyMap.DestinationProperty.MemberInfo)) { continue; } var propertyTypeMap = ConfigurationProvider.ResolveTypeMap(result.Type, propertyMap.DestinationPropertyType); var propertyRequest = new ExpressionRequest(result.Type, propertyMap.DestinationPropertyType, request.MembersToExpand); var binder = Binders.FirstOrDefault(b => b.IsMatch(propertyMap, propertyTypeMap, result)); if (binder == null) { var message = $"Unable to create a map expression from {propertyMap.SourceMember?.DeclaringType?.Name}.{propertyMap.SourceMember?.Name} ({result.Type}) to {propertyMap.DestinationProperty.MemberInfo.DeclaringType?.Name}.{propertyMap.DestinationProperty.Name} ({propertyMap.DestinationPropertyType})"; throw new AutoMapperMappingException(message); } var bindExpression = binder.Build(this, propertyMap, propertyTypeMap, propertyRequest, result, typePairCount); bindings.Add(bindExpression); } return(bindings); }