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