示例#1
0
        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);
        }
示例#3
0
 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;
 }
示例#4
0
        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));
 }
示例#7
0
        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);
        }