-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Closed
Description
We ran into a very corner cased problem which is as follows:
- When
MapAtRuntimeis used - When mapping for example from
inttoint? - When using a extension method in the source mapping
The following Exception shows up:
System.ArgumentException: Expression of type 'System.Nullable`1[System.Int32]' cannot be used for parameter of type 'System.Int32' of method 'System.Nullable`1[System.Int32] MapInternal[Int32,Nullable`1](Int32, System.Nullable`1[System.Int32], AutoMapper.MemberMap)' (Parameter 'arg0')
at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1, Expression arg2)
at AutoMapper.Execution.ExpressionBuilder.ContextMap(TypePair typePair, Expression sourceParameter, Expression destinationParameter, MemberMap memberMap)
at AutoMapper.Execution.TypeMapPlanBuilder.MapMember(MemberMap memberMap, ParameterExpression resolvedValue, Expression destinationMemberValue)
at AutoMapper.Execution.TypeMapPlanBuilder.CreatePropertyMapFunc(MemberMap memberMap, Expression destination, MemberInfo destinationMember)
at AutoMapper.Execution.TypeMapPlanBuilder.AddPropertyMaps(List`1 actions)
at AutoMapper.Execution.TypeMapPlanBuilder.CreateAssignmentFunc(Expression createDestination)
at AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda()
at AutoMapper.TypeMap.CreateMapperLambda(IGlobalConfiguration configuration)
at AutoMapper.TypeMap.Seal(IGlobalConfiguration configuration)
at AutoMapper.MapperConfiguration.<.ctor>g__Seal|20_0()
at AutoMapper.MapperConfiguration..ctor(MapperConfigurationExpression configurationExpression)
at Program.<Main>$(String[] args) in Program.cs:line 12Here is a minimal reproduceable for the problem:
using AutoMapper;
var cfg = new MapperConfigurationExpression();
cfg.CreateMap<SourceObject, DestObject>()
.ForMember(dest => dest.MyValue, opt =>
{
opt.MapFrom(src => StringExtensions.ExtractInt(src.MyValue));
opt.MapAtRuntime();
});
var mapper = new MapperConfiguration(cfg).CreateMapper();
var s = new SourceObject { MyValue = "1" };
var d = mapper.Map<SourceObject, DestObject>(s);
Console.WriteLine(d.MyValue);
class SourceObject { public string MyValue { get; set; } }
class DestObject { public int? MyValue { get; set; } }
static class StringExtensions
{
public static int ExtractInt(this string str) => int.Parse(str);
}
Removing the this in the extension methods makes everything work.
For what it's worth, the "difference" in the code is here:
| if (chain.Count < min || chain.Peek().Target is not ParameterExpression parameter) |
For the extension method, the chain is actual equal to min, while with non extension methods, the chain count is 0.
I think, this here was the same problem:
#3819
Thanks,
Philipp
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels