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