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