protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { var destinationElementType = destination.Type.ExtractCollectionType(); var shouldConvert = destination.Type.GetMethod("Add", new[] { destinationElementType }) == null; //var list = (ICollection<>)dest; var actions = new List <Expression>(); var list = destination; if (shouldConvert) { var listType = destination.Type.GetGenericEnumerableType() != null ? typeof(ICollection <>).MakeGenericType(destinationElementType) : typeof(IList); list = Expression.Variable(listType, "list"); actions.Add(ExpressionEx.Assign(list, destination)); //convert to list type } //list.Clear(); if (arg.MapType == MapType.MapToTarget) { var clear = list.Type.GetMethod("Clear", Type.EmptyTypes); actions.Add(Expression.Call(list, clear)); } actions.Add(CreateListSet(source, list, arg)); if (shouldConvert) { return(Expression.Block(new[] { (ParameterExpression)list }, actions)); } return(Expression.Block(actions)); }
protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { if (destination.Type.IsArray) { if (source.Type.IsArray && source.Type.GetElementType() == destination.Type.GetElementType() && source.Type.GetElementType().UnwrapNullable().IsConvertible()) { //Array.Copy(src, 0, dest, 0, src.Length) var method = typeof(Array).GetMethod("Copy", new[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) }); return(Expression.Call(method, source, Expression.Constant(0), destination, Expression.Constant(0), Expression.ArrayLength(source))); } else { return(CreateArraySet(source, destination, arg)); } } else { var destinationElementType = destination.Type.ExtractCollectionType(); var listType = destination.Type.GetGenericEnumerableType() != null ? typeof(ICollection <>).MakeGenericType(destinationElementType) : typeof(IList); var tmp = Expression.Variable(listType); var assign = ExpressionEx.Assign(tmp, destination); //convert to list type var set = CreateListSet(source, tmp, arg); return(Expression.Block(new[] { tmp }, assign, set)); } }
private LambdaExpression CreateDynamicMapExpression(TypeTuple tuple) { var lambda = CreateMapExpression(tuple, MapType.Map); var pNew = Expression.Parameter(typeof(object)); var pOld = lambda.Parameters[0]; var assign = ExpressionEx.Assign(pOld, pNew); return(Expression.Lambda( Expression.Block(new[] { pOld }, assign, lambda.Body), pNew)); }
private static Expression InvokeMapping(Func <CompileArgument, LambdaExpression> mappingFactory, Expression source, Expression result, CompileArgument arg, bool setResult) { var afterMapping = mappingFactory(arg); var args = afterMapping.Parameters; var invoke = afterMapping.Apply(arg.MapType, source.To(args[0].Type), result.To(args[1].Type)); if (invoke.Type != typeof(void) && setResult) { invoke = ExpressionEx.Assign(result, invoke); } return(invoke); }
protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { var destinationElementType = destination.Type.ExtractCollectionType(); var listType = destination.Type.GetGenericEnumerableType() != null ? typeof(ICollection <>).MakeGenericType(destinationElementType) : typeof(IList); var tmp = Expression.Variable(listType, "list"); var assign = ExpressionEx.Assign(tmp, destination); //convert to list type var set = CreateListSet(source, tmp, arg); return(Expression.Block(new[] { tmp }, assign, set)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.PreserveReference == true && arg.MapType != MapType.Projection && !arg.SourceType.GetTypeInfo().IsValueType&& !arg.DestinationType.GetTypeInfo().IsValueType) { var dict = Expression.Parameter(typeof(Dictionary <object, object>)); var propInfo = typeof(MapContext).GetProperty("Context", BindingFlags.Static | BindingFlags.Public); var refContext = Expression.Property(null, propInfo); var refDict = Expression.Property(refContext, "References"); var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object))); set = 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 assignDict = Expression.Assign(dict, refDict); set = Expression.IfThenElse( checkHasRef, ExpressionEx.Assign(result, cached), set); set = Expression.Block(new[] { cached, dict }, assignDict, set); } else { set = Expression.Block(assign, set); } if (arg.MapType != MapType.Projection && (!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 override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { if (destination.Type.IsArray) { return(CreateArraySet(source, destination, arg)); } else { var destinationElementType = destination.Type.ExtractCollectionType(); var listType = destination.Type.IsGenericEnumerableType() || destination.Type.GetInterfaces().Any(ReflectionUtils.IsGenericEnumerableType) ? typeof(ICollection <>).MakeGenericType(destinationElementType) : typeof(IList); var tmp = Expression.Variable(listType); var assign = ExpressionEx.Assign(tmp, destination); //convert to list type var set = CreateListSet(source, tmp, arg); return(Expression.Block(new[] { tmp }, assign, set)); } }
protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { var destinationElementType = destination.Type.ExtractCollectionType(); var listType = destination.Type.GetGenericEnumerableType() != null ? typeof(ICollection <>).MakeGenericType(destinationElementType) : typeof(IList); var tmp = Expression.Variable(listType, "list"); var actions = new List <Expression> { ExpressionEx.Assign(tmp, destination) //convert to list type }; if (arg.MapType == MapType.MapToTarget) { var clear = listType.GetMethod("Clear", Type.EmptyTypes); actions.Add(Expression.Call(tmp, clear)); } actions.Add(CreateListSet(source, tmp, arg)); return(Expression.Block(new[] { tmp }, actions)); }
protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg) { var result = Expression.Variable(arg.DestinationType); Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg)); var set = CreateBlockExpression(source, result, arg); if (arg.Settings.PreserveReference == true && arg.MapType != MapType.Projection && !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.MapType != MapType.Projection && (!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)); }
private Expression CreateArraySet(Expression source, Expression destination, CompileArgument arg) { //var v0 = 0, v1 = 0; //var vlen0 = dest.GetLength(0), vlen1 = dest.GetLength(1); //for (var i = 0, len = src.Count; i < len; i++) { // var item = src[i]; // dest[v0, v1] = convert(item); // v1++; // if (v1 >= vlen1) { // v1 = 0; // v0++; // } //} var sourceElementType = source.Type.ExtractCollectionType(); var destinationElementType = destination.Type.ExtractCollectionType(); var item = Expression.Variable(sourceElementType, "item"); var vx = Enumerable.Range(0, destination.Type.GetArrayRank()) .Select(i => Expression.Variable(typeof(int), "v" + i)) .ToList(); var vlenx = Enumerable.Range(0, destination.Type.GetArrayRank()) .Select(i => Expression.Variable(typeof(int), "vlen" + i)) .ToList(); var block = new List <Expression>(); block.AddRange(vx.Select(v => Expression.Assign(v, Expression.Constant(0)))); var method = typeof(Array).GetMethod("GetLength", new[] { typeof(int) }); block.AddRange( vlenx.Select((vlen, i) => Expression.Assign( vlen, Expression.Call(destination, method, Expression.Constant(i))))); var getter = CreateAdaptExpression(item, destinationElementType, arg); var set = ExpressionEx.Assign( Expression.ArrayAccess(destination, vx), getter); Expression ifExpr = Expression.Block( Expression.Assign(vx[1], Expression.Constant(0)), Expression.PostIncrementAssign(vx[0])); for (var i = 1; i < vx.Count; i++) { var list = new List <Expression>(); if (i + 1 < vx.Count) { list.Add(Expression.Assign(vx[i + 1], Expression.Constant(0))); } list.Add(Expression.PostIncrementAssign(vx[i])); list.Add(Expression.IfThen( Expression.GreaterThanOrEqual(vx[i], vlenx[i]), ifExpr)); ifExpr = Expression.Block(list); } var loop = ExpressionEx.ForLoop(source, item, set, ifExpr); block.Add(loop); return(Expression.Block(vx.Concat(vlenx), block)); }
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 override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) { var dictArgs = destination.Type.GetDictionaryType() !.GetGenericArguments(); var shouldConvert = destination.Type.GetMethod("Add", dictArgs) == null; //var dict = (IDictionary<,>)dest; var actions = new List <Expression>(); var dict = destination; if (shouldConvert) { var dictType = typeof(IDictionary <,>).MakeGenericType(dictArgs); dict = Expression.Variable(dictType, "dict"); actions.Add(ExpressionEx.Assign(dict, destination)); //convert to dict type } var mapped = base.CreateBlockExpression(source, dict, arg); if (mapped.NodeType != ExpressionType.Default) { actions.Add(mapped); } //if source is not dict type, use ClassAdapter only var srcDictType = arg.SourceType.GetDictionaryType(); if (srcDictType == null || arg.Settings.IgnoreNonMapped == true) { return(shouldConvert && mapped.NodeType != ExpressionType.Default ? Expression.Block(new[] { (ParameterExpression)dict }, actions) : mapped); } var keyType = srcDictType.GetGenericArguments().First(); var kvpType = source.Type.ExtractCollectionType(); var kvp = Expression.Variable(kvpType, "kvp"); var key = Expression.Variable(keyType, "key"); var keyAssign = Expression.Assign(key, Expression.Property(kvp, "Key")); //dest[kvp.Key] = convert(kvp.Value); var set = CreateSetFromKvp(kvp, key, dict, arg); if (arg.Settings.NameMatchingStrategy.SourceMemberNameConverter != NameMatchingStrategy.Identity) { set = Expression.Block( Expression.Assign( key, Expression.Call( MapsterHelper.GetConverterExpression(arg.Settings.NameMatchingStrategy.SourceMemberNameConverter), "Invoke", null, key)), set); } //ignore mapped var ignores = arg.Settings.Resolvers .Select(r => r.SourceMemberName) .Where(name => name != null) .ToHashSet(); //ignore var ignoreIfs = new Dictionary <string, Expression>(); foreach (var ignore in arg.Settings.Ignore) { if (ignore.Value.Condition == null) { ignores.Add(ignore.Key); } else { var body = ignore.Value.IsChildPath ? ignore.Value.Condition.Body : ignore.Value.Condition.Apply(arg.MapType, source, dict); var setWithCondition = Expression.IfThen( ExpressionEx.Not(body), set); ignoreIfs.Add(ignore.Key, setWithCondition); } } //dict to switch if (ignoreIfs.Count > 0 || ignores.Count > 0) { var cases = ignoreIfs .Select(k => Expression.SwitchCase(k.Value, Expression.Constant(k.Key))) .ToList(); if (ignores.Count > 0) { cases.Add(Expression.SwitchCase(Expression.Empty(), ignores.Select(Expression.Constant))); } set = Expression.Switch(typeof(void), key, set, null, cases); } //if (kvp.Value != null) // dest[kvp.Key] = convert(kvp.Value); var kvpValueType = kvpType.GetGenericArguments()[1]; if (arg.Settings.IgnoreNullValues == true && kvpValueType.CanBeNull()) { set = Expression.IfThen( Expression.NotEqual( Expression.Property(kvp, "Value"), Expression.Constant(null, kvpValueType)), set); } //foreach (var kvp in source) { // dest[kvp.Key] = convert(kvp.Value); //} set = Expression.Block(new[] { key }, keyAssign, set); var loop = ExpressionEx.ForEach(source, kvp, set); actions.Add(loop); return(shouldConvert ? Expression.Block(new[] { (ParameterExpression)dict }, actions) : Expression.Block(actions)); }
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)); }