示例#1
0
        private static Func <Foo, Bar> CreateReader(IMappingAssociation association)
        {
            var factory = new MapperFactory(
                new TestMap(typeof(Foo), typeof(Bar), association),
                new TestMap(typeof(Baz), typeof(Qux))
                );

            return(_ => factory.GetReader <Foo, Bar>()(_, null));
        }
示例#2
0
        private static Action <Bar, Foo> CreateWriter(IMappingAssociation association)
        {
            var factory = new MapperFactory(
                new TestMap(typeof(Foo), typeof(Bar), association),
                new TestMap(typeof(Baz), typeof(Qux))
                );

            return((source, target) => factory.GetWriter <Bar, Foo>()(source, target, null));
        }
            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                var instance = Visit(node.Object);

                PropertyInfo           collectionProp;
                IMappingAssociation    assoc      = null;
                ICollectionAssociation collection = null;
                Type itemType = null;

                if (node.Arguments.Any(a =>
                                       a.TryGetProperty(out collectionProp) && //it's a property
                                       _ctx.Associations.TryGetValue(collectionProp.GetName(), out assoc) &&
                                       (collection = assoc as ICollectionAssociation) != null //it's a collection property
                                       ))
                {
                    itemType = collection.TargetItemType;
                }

                var args = node.Arguments.Select(a =>
                {
                    var lambda = a as LambdaExpression;

                    if (itemType != null && assoc != null && lambda != null && lambda.Parameters.Count == 1 && ((lambda.Parameters[0].Type) == itemType))
                    {
                        var component = assoc as IComponentAssociation;
                        if ((component != null) && (itemType == component.ComponentKey.Low || itemType == component.ComponentKey.High))
                        {
                            var ctx = new MapContext
                            {
                                From         = itemType,
                                To           = itemType == component.ComponentKey.Low ? component.ComponentKey.High : component.ComponentKey.Low,
                                Associations = _mapper._associations[component.ComponentKey]
                            };

                            var preserved = _ctx;
                            _ctx          = ctx;
                            var result    = Visit(lambda);
                            _ctx          = preserved;

                            return(result);
                        }

                        var converter = assoc as IConvertionAssociation;
                        LambdaExpression conversion;
                        if (converter != null && itemType == (conversion = converter.TargetConverter.Expression).ReturnType)
                        {
                            var body = lambda.Apply(conversion.Body);

                            return(Expression.Lambda(body, conversion.Parameters[0]));
                        }
                    }

                    return(Visit(a));
                }).ToArray();

                if (instance == node.Object && args.SequenceEqual(node.Arguments))
                {
                    return(node);
                }

                var          method = node.Method;
                PropertyInfo oldProp;
                PropertyInfo newProp;

                if (method.IsGenericMethod &&
                    method.IsStatic &&
                    method.DeclaringType == typeof(Enumerable) &&
                    node.Arguments[0].TryGetProperty(out oldProp) &&
                    args[0].TryGetProperty(out newProp) &&
                    oldProp.PropertyType != newProp.PropertyType
                    )
                {
                    var baseMethod = method.GetGenericMethodDefinition();

                    method = baseMethod.MakeGenericMethod(newProp.PropertyType.GetItemType());

                    return(Expression.Call(null, method, args));
                }

                return(Expression.Call(instance, node.Method, args));
            }
示例#4
0
        private Expression BuildWriterItem(IMappingAssociation association, Expression from, Expression to, ParameterExpression explicitProperties)
        {
            if ((association.Direction & MappingDirection.Write) != MappingDirection.Write)
            {
                return(null);
            }

            var converter = association as IConvertionAssociation;
            var component = association as IComponentAssociation;

            var donor    = association.Target.Apply(@from);
            var acceptor = association.Source.Apply(to);

            Expression result;

            if (component != null)
            {
                //todo: probably should filterout expand somehow. E.g. 'foo.id' should become 'id'. Now simply not passing outer expand
                result = BuildWriterBody(donor, acceptor, null);

                if (result.NodeType == ExpressionType.Default && result.Type == typeof(void))
                {
                    return(null);
                }
            }
            else
            {
                PropertyInfo prop;
                if (!acceptor.TryGetProperty(out prop))
                {
                    throw new InvalidOperationException(
                              string.Format("Mapping from source:{0} to target:{1} marked as writable but source is not a property access expression", association.Source.Stringify(), association.Target.Stringify())
                              );
                }

                result = Expression.Assign(
                    acceptor,
                    converter == null ? donor : converter.TargetConverter.Expression.Apply(donor)
                    );
            }

            if (!(donor.Type.IsValueType || (result.NodeType == ExpressionType.Assign && ((BinaryExpression)result).Right == donor)))
            {
                result = Expression.IfThenElse(
                    donor.CreateCheckForDefault(),
                    Expression.Assign(acceptor, acceptor.Type.GetDefaultExpression()),
                    result
                    );
            }

            if (explicitProperties != null)
            {
                result = Expression.IfThen(
                    Expression.OrElse(
                        explicitProperties.CreateCheckForDefault(),
                        explicitProperties.CreateContains(Expression.Constant(association.Key, typeof(string)))
                        ),
                    result
                    );
            }

            return(result);
        }
示例#5
0
        private Expression BuildReaderItem(IMappingAssociation association, Expression from, ParameterExpression expands)
        {
            if ((association.Direction & MappingDirection.Read) != MappingDirection.Read)
            {
                return(null);
            }

            var converter  = association as IConvertionAssociation;
            var collection = association as ICollectionAssociation;
            var component  = association as IComponentAssociation;
            var expandable = association as IExpandableAssociation;

            Expression result;

            var donor = association.Source.Apply(from);

            var targetType = association.Target.ReturnType;

            if (collection != null)
            {
                LambdaExpression selector;

                //selector = new component { ... }
                if (component != null)
                {
                    var param = Expression.Parameter(collection.SourceItemType);

                    //todo: probably should filterout expand somehow. E.g. 'foo.id' should become 'id'. Now simply not passing outer expand
                    var body = BuildReaderBody(param, collection.TargetItemType, null);

                    selector = Expression.Lambda(body, param);
                }
                //selector = converter
                else if (converter != null)
                {
                    selector = converter.TargetConverter.Expression;
                }
                else
                {
                    throw new InvalidOperationException();
                }

                // from.prop.select(selector).toarray().asenumerable()
                result =
                    Expression.Convert(
                        Expression.Call(
                            ToArray.MakeGenericMethod(collection.TargetItemType),
                            Expression.Call(
                                Select.MakeGenericMethod(collection.SourceItemType, collection.TargetItemType),
                                donor,
                                selector
                                )
                            ),
                        targetType
                        );
            }
            else
            {
                // new component { .... }
                if (component != null)
                {
                    //todo: probably should filterout expand somehow. E.g. 'foo.id' should become 'id'. Now simply not passing outer expand
                    result = BuildReaderBody(donor, targetType, null);
                }
                //-or- converter(from.prop)
                else if (converter != null)
                {
                    result = converter.SourceConverter.Expression.Apply(donor);
                }
                // from.prop
                else
                {
                    result = donor;
                }
            }

            // expands.contains({key}) ? {exp} : null
            if (result != null && expands != null && expandable != null && expandable.Expand)
            {
                result = Expression.Condition(
                    expands.CreateContains(Expression.Constant(association.Key, typeof(string))),
                    result,
                    targetType.GetDefaultExpression()
                    );
            }

            // from.prop != null ? null : {exp}
            if (!(donor.Type.IsValueType || result == donor))
            {
                result = Expression.Condition(
                    donor.CreateCheckForDefault(),
                    targetType.GetDefaultExpression(),
                    result
                    );
            }

            return(result);
        }