/// <summary>
        /// Get the right creator delegate from the cache depending on the real type of the source.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static Func <TSource, IncludeChain, TTarget> GetCreatorByType(Tuple <Type, MapMode> key)
        {
            return(_CacheCreators.GetOrAdd(key, k =>
            {
                Type sourceType = typeof(TSource);
                Type targetType = typeof(TTarget);

                ParameterExpression paramSource = Expression.Parameter(sourceType);
                ParameterExpression paramInclude = Expression.Parameter(typeof(IncludeChain));
                Dictionary <Type, GenericAssociation> genericTypeAssociation;
                var mapInfo = MapInfo.Get(k.Item1, targetType, false, out genericTypeAssociation);
                if (mapInfo == null)
                {
                    return (source, include) => default(TTarget);
                }
                var builderExpr = MapBuilder.CreateBuilderExpression(
                    mapMode: k.Item2,
                    mapInfo: mapInfo,
                    genericTypeAssociation: genericTypeAssociation,
                    paramSource: paramSource,
                    varResult: null,
                    paramIncludeChain: paramInclude,
                    usedBuilders: null);

                var body = mapInfo.UseItemsCache ?
                           MapperCache.GetOrSet(
                    paramSource,
                    targetType,
                    paramInclude,
                    builderExpr)
                    : builderExpr;

                return Expression.Lambda <Func <TSource, IncludeChain, TTarget> >(
                    body,
                    paramSource,
                    paramInclude
                    ).Compile();
            }));
        }
        /// <summary>
        /// Get the expression that fills an instance. Call GetPolymorphedFiller(source.GetType(), target.GetType()) if polymorphic.
        /// </summary>
        /// <param name="mapMode"></param>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="includeChain"></param>
        /// <returns></returns>
        internal static Expression GetMostConcreteExpressionFiller(MapMode mapMode, Expression source, Expression target, Expression includeChain)
        {
            Dictionary <Type, GenericAssociation> genericTypeAssociation = null;

            if (MapInfo._PolymorphTypes.Contains(source.Type))
            {
                return(Expression.Call(
                           Expression.Call(
                               typeof(PolymorphismManager <,>).MakeGenericType(source.Type, target.Type).GetMethod(nameof(PolymorphismManager <object, object> .GetFillerByType)),
                               Expression.Call(
                                   Meta.Method(() => Tuple.Create <Type, Type, MapMode>(null, null, MapMode.All)),
                                   Expression.Call(source, typeof(object).GetMethod("GetType")),
                                   Expression.Call(target, typeof(object).GetMethod("GetType")),
                                   Expression.Constant(mapMode)
                                   )),
                           typeof(Action <, ,>).MakeGenericType(source.Type, target.Type, typeof(IncludeChain)).GetMethod("Invoke"),
                           source,
                           target,
                           includeChain
                           ));
            }
            else
            {
                MapInfo mapInfo = MapInfo.Get(source.Type, target.Type, true, out genericTypeAssociation);
                if (mapInfo == null)
                {
                    return(target.Type.IsAssignableFrom(source.Type) ? source : null);
                }

                return(MapBuilder.CreateBuilderExpression(
                           mapMode: mapMode,
                           mapInfo: mapInfo,
                           genericTypeAssociation: genericTypeAssociation,
                           paramSource: source,
                           varResult: target,
                           paramIncludeChain: includeChain,
                           usedBuilders: null));
            }
        }
 /// <summary>
 /// Get the right filler delegate from the cache depending on the real type of the source and the target.
 /// </summary>
 /// <param name="key"></param>
 /// <returns></returns>
 public static Action <TSource, TTarget, IncludeChain> GetFillerByType(Tuple <Type, Type, MapMode> key)
 {
     return(_CacheFillers.GetOrAdd(key, k =>
     {
         Type sourceType = typeof(TSource);
         Type targetRealType = k.Item2;
         ParameterExpression paramSource = Expression.Parameter(sourceType);
         ParameterExpression paramTarget = Expression.Parameter(typeof(TTarget));
         ParameterExpression paramInclude = Expression.Parameter(typeof(IncludeChain));
         ParameterExpression varRealTypeTarget = Expression.Parameter(targetRealType);
         Dictionary <Type, GenericAssociation> genericTypeAssociation;
         var mapInfo = MapInfo.Get(k.Item1, targetRealType, true, out genericTypeAssociation);
         if (mapInfo == null)
         {
             return (source, target, include) => { }
         }
         ;
         var body = Expression.Block(
             new ParameterExpression[] { varRealTypeTarget },
             Expression.Assign(varRealTypeTarget, paramTarget.Convert(targetRealType)),
             MapBuilder.CreateBuilderExpression(
                 mapMode: k.Item3,
                 mapInfo: mapInfo,
                 genericTypeAssociation: genericTypeAssociation,
                 paramSource: paramSource,
                 varResult: varRealTypeTarget,
                 paramIncludeChain: paramInclude,
                 usedBuilders: null),
             varRealTypeTarget
             );
         return Expression.Lambda <Action <TSource, TTarget, IncludeChain> >(
             body,
             paramSource,
             paramTarget,
             paramInclude
             ).Compile();
     }));
 }
        /// <summary>
        /// Get the expression that creates an instance. Call GetPolymorphedCreator(source.GetType()) if polymorphic.
        /// </summary>
        /// <param name="mapMode"></param>
        /// <param name="source"></param>
        /// <param name="targetType"></param>
        /// <param name="sourceType"></param>
        /// <param name="includeChain"></param>
        /// <param name="usedBuilders"></param>
        /// <returns></returns>
        internal static Expression GetMostConcreteExpressionCreator(MapMode mapMode, Expression source, Type targetType, Expression includeChain, List <Tuple <Type, Type> > usedBuilders)
        {
            Dictionary <Type, GenericAssociation> genericTypeAssociation;
            Expression builderExpression;

            if (MapInfo._PolymorphTypes.Contains(source.Type) || usedBuilders.Contains(Tuple.Create(source.Type, targetType)))
            {
                Expression sourceTypeExpr = MapInfo._PolymorphTypes.Contains(source.Type) ?
                                            (Expression)Expression.Call(source, typeof(object).GetMethod("GetType"))
                    : Expression.Constant(source.Type);

                builderExpression = Expression.Call(
                    Expression.Call(
                        typeof(PolymorphismManager <,>).MakeGenericType(source.Type, targetType).GetMethod(nameof(PolymorphismManager <object, object> .GetCreatorByType)),
                        Expression.Call(
                            Meta.Method(() => Tuple.Create <Type, MapMode>(null, MapMode.All)),
                            sourceTypeExpr,
                            Expression.Constant(mapMode)
                            )),
                    typeof(Func <, ,>).MakeGenericType(source.Type, typeof(IncludeChain), targetType).GetMethod("Invoke"),
                    source,
                    includeChain
                    );
            }
            else
            {
                MapInfo mapInfo = MapInfo.Get(source.Type, targetType, false, out genericTypeAssociation);
                if (mapInfo == null)
                {
                    return(targetType.IsAssignableFrom(source.Type) ? source.Convert(targetType) : null);
                }

                var actualBuilderExpression = MapBuilder.CreateBuilderExpression(
                    mapMode: mapMode,
                    mapInfo: mapInfo,
                    genericTypeAssociation: genericTypeAssociation,
                    paramSource: source,
                    varResult: null,
                    paramIncludeChain: includeChain,
                    usedBuilders: usedBuilders.ToList());
                builderExpression = mapInfo.UseItemsCache ? MapperCache.GetOrSet(source, targetType, includeChain, actualBuilderExpression) : actualBuilderExpression;
            }
            if (builderExpression == null)
            {
                return(null);
            }

            var resultVar = Expression.Variable(targetType);

            Expression result;

            if (source.Type.IsSimpleType()) // enums. Simple types have been handled earlier.
            {
                result = builderExpression;
            }
            else
            {
                result = Expression.Block(
                    new ParameterExpression[] { resultVar },
                    Expression.IfThenElse(
                        Expression.Equal(source, Expression.Default(source.Type)),
                        Expression.Assign(resultVar, Expression.Default(targetType)),
                        Expression.Assign(resultVar, builderExpression)
                        ),
                    resultVar
                    );
            }
            return(result);
        }