Exemple #1
0
        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));
     }
 }
Exemple #3
0
        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));
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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));
        }
Exemple #6
0
        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));
        }
Exemple #7
0
 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));
        }
Exemple #9
0
        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));
        }
Exemple #11
0
        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));
        }
Exemple #12
0
        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));
        }
Exemple #13
0
        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));
        }