protected Expression CreateAdaptToExpression(Expression source, Expression destination, CompileArgument arg) { if (destination == null) { return(CreateAdaptExpression(source, arg.DestinationType, arg)); } if (source.Type == destination.Type && arg.Settings.ShallowCopyForSameType == true) { return(source); } //adapt(source, dest); var lambda = arg.Context.Config.CreateInlineMapExpression(source.Type, destination.Type, arg.MapType, arg.Context); var exp = lambda.Apply(source, destination); //transform(adapt(source, dest)); if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type)) { var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type]; var replacer = new ParameterExpressionReplacer(transform.Parameters, exp); var newExp = replacer.Visit(transform.Body); exp = replacer.ReplaceCount >= 2 ? Expression.Invoke(transform, exp) : newExp; } return(exp.To(destination.Type)); }
protected Expression CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg) { if (source.Type == destinationType && (arg.Settings.ShallowCopyForSameType == true || arg.MapType == MapType.Projection)) return source.To(destinationType); var lambda = arg.Context.Config.CreateInlineMapExpression(source.Type, destinationType, arg.MapType, arg.Context); var exp = lambda.Apply(source); if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type)) { var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type]; var replacer = new ParameterExpressionReplacer(transform.Parameters, exp); var newExp = replacer.Visit(transform.Body); exp = replacer.ReplaceCount >= 2 ? Expression.Invoke(transform, exp) : newExp; } return exp.To(destinationType); }
public static Expression Apply(this LambdaExpression lambda, params Expression[] exps) { var replacer = new ParameterExpressionReplacer(lambda.Parameters, exps); return replacer.Visit(lambda.Body); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) { throw new InvalidOperationException( $"Mapping is invalid for projection: TSource: {arg.SourceType} TDestination: {arg.DestinationType}"); } var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.AfterMappingFactories.Count > 0) { //var result = adapt(source); //action(source, result); var actions = new List <Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType&& !arg.DestinationType.GetTypeInfo().IsValueType) { //using (var scope = new MapContextScope()) { // var dict = scope.Context.Reference; // object cache; // if (dict.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // dict.Add(source, (object)result); // result.Prop1 = adapt(source.Prop1); // result.Prop2 = adapt(source.Prop2); // } //} var scope = Expression.Variable(typeof(MapContextScope)); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dict = Expression.Variable(typeof(Dictionary <object, object>)); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAdd, set); var cached = Expression.Variable(typeof(object)); var tryGetMethod = typeof(Dictionary <object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cached); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cached), setResultAndCache); var usingBody = Expression.Block(new[] { cached, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else // result = adapt(source); //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } return(Expression.Block(new[] { result }, set, result)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) { throw new InvalidOperationException("Mapping is invalid for projection"); } //var result = new TDest(); var result = Expression.Variable(arg.DestinationType, "result"); var newObj = CreateInstantiationExpression(source, destination, arg); Expression assign = Expression.Assign(result, newObj); var set = CreateBlockExpression(source, result, arg); //result.prop = adapt(source.prop); //action(source, result); if (arg.Settings.AfterMappingFactories.Count > 0) { var actions = new List <Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } //using (var scope = new MapContextScope()) { // var references = scope.Context.Reference; // object cache; // if (references.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // references[source] = (object)result; // result.prop = adapt(source.prop); // } //} if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType&& !arg.DestinationType.GetTypeInfo().IsValueType) { var scope = Expression.Variable(typeof(MapContextScope), "scope"); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dictType = typeof(Dictionary <object, object>); var dict = Expression.Variable(dictType, "references"); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var indexer = dictType.GetProperties().First(item => item.GetIndexParameters().Length > 0); var refAssign = Expression.Assign( Expression.Property(dict, indexer, Expression.Convert(source, typeof(object))), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAssign, set); var cache = Expression.Variable(typeof(object), "cache"); var tryGetMethod = typeof(Dictionary <object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cache); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cache), setResultAndCache); var usingBody = Expression.Block(new[] { cache, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else { // result = new TDestination(); // result.prop = adapt(source.prop); //} //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } //var drvdSource = source as TDerivedSource //if (drvdSource != null) // result = adapt<TSource, TDest>(drvdSource); //else { // result = new TDestination(); // result.prop = adapt(source.prop); //} //return result; foreach (var tuple in arg.Settings.Includes) { //same type, no redirect to prevent endless loop if (tuple.Source == arg.SourceType) { continue; } //type is not compatible, no redirect if (!arg.SourceType.IsReferenceAssignableFrom(tuple.Source)) { continue; } var blocks = new List <Expression>(); var vars = new List <ParameterExpression>(); var drvdSource = Expression.Variable(tuple.Source); vars.Add(drvdSource); var drvdSourceAssign = Expression.Assign( drvdSource, Expression.TypeAs(source, tuple.Source)); blocks.Add(drvdSourceAssign); var cond = Expression.NotEqual(drvdSource, Expression.Constant(null, tuple.Source)); ParameterExpression drvdDest = null; if (destination != null) { drvdDest = Expression.Variable(tuple.Destination); vars.Add(drvdDest); var drvdDestAssign = Expression.Assign( drvdDest, Expression.TypeAs(destination, tuple.Destination)); blocks.Add(drvdDestAssign); cond = Expression.AndAlso( cond, Expression.NotEqual(drvdDest, Expression.Constant(null, tuple.Destination))); } var adaptExpr = drvdDest == null ? CreateAdaptExpression(drvdSource, tuple.Destination, arg) : CreateAdaptToExpression(drvdSource, drvdDest, arg); var adapt = Expression.Assign(result, adaptExpr); var ifExpr = Expression.Condition(cond, adapt, set, typeof(void)); blocks.Add(ifExpr); set = Expression.Block(vars, blocks); } return(Expression.Block(new[] { result }, set, result)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { if (arg.MapType == MapType.Projection) throw new InvalidOperationException( $"Mapping is invalid for projection: TSource: {arg.SourceType} TDestination: {arg.DestinationType}"); var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.AfterMappingFactories.Count > 0) { //var result = adapt(source); //action(source, result); var actions = new List<Expression> { set }; foreach (var afterMappingFactory in arg.Settings.AfterMappingFactories) { var afterMapping = afterMappingFactory(arg); var args = afterMapping.Parameters; Expression invoke; if (args[0].Type.IsReferenceAssignableFrom(source.Type) && args[1].Type.IsReferenceAssignableFrom(result.Type)) { var replacer = new ParameterExpressionReplacer(args, source, result); invoke = replacer.Visit(afterMapping.Body); } else { invoke = Expression.Invoke(afterMapping, source.To(args[0].Type), result.To(args[1].Type)); } actions.Add(invoke); } set = Expression.Block(actions); } if (arg.Settings.PreserveReference == true && !arg.SourceType.GetTypeInfo().IsValueType && !arg.DestinationType.GetTypeInfo().IsValueType) { //using (var scope = new MapContextScope()) { // var dict = scope.Context.Reference; // object cache; // if (dict.TryGetValue(source, out cache)) // result = (TDestination)cache; // else { // result = new TDestination(); // dict.Add(source, (object)result); // result.Prop1 = adapt(source.Prop1); // result.Prop2 = adapt(source.Prop2); // } //} var scope = Expression.Variable(typeof(MapContextScope)); var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope))); var dict = Expression.Variable(typeof(Dictionary<object, object>)); var refContext = Expression.Property(scope, "Context"); var refDict = Expression.Property(refContext, "References"); var assignDict = Expression.Assign(dict, refDict); var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object))); var setResultAndCache = Expression.Block(assign, refAdd, set); var cached = Expression.Variable(typeof(object)); var tryGetMethod = typeof(Dictionary<object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() }); var checkHasRef = Expression.Call(dict, tryGetMethod, source, cached); var setResult = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cached), setResultAndCache); var usingBody = Expression.Block(new[] { cached, dict }, assignDict, setResult); var dispose = Expression.Call(scope, "Dispose", null); set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose)); } else { set = Expression.Block(assign, set); } //TDestination result; //if (source == null) // result = default(TDestination); //else // result = adapt(source); //return result; if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()) { var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type)); set = Expression.IfThenElse( compareNull, Expression.Assign(result, destination ?? Expression.Constant(arg.DestinationType.GetDefault(), arg.DestinationType)), set); } return Expression.Block(new[] { result }, set, result); }