Cannot convert expressions that are for a struct property to non-struct properties
yinzara opened this issue · 3 comments
This defect seems to have been introduced in the v12 release.
I think it might actually be caused by:
#144
When attempting to map expressions between properties that are convertible types but one type is a struct and the other is a class, an exception is thrown (instead of the mapping being valid).
ystem.InvalidOperationException : No coercion operator is defined between types 'MyStructType' and 'MyClassType'.
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at AutoMapper.Extensions.ExpressionMapping.Extensions.VisitorExtensions.ConvertTypeIfNecessary(Expression expression, Type memberType)
at AutoMapper.Extensions.ExpressionMapping.XpressionMapperVisitor.<VisitMember>g__GetMappedMemberExpression|17_0(Expression parentExpression, List`1 propertyMapInfoList, <>c__DisplayClass17_0& )
at AutoMapper.Extensions.ExpressionMapping.XpressionMapperVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at AutoMapper.Extensions.ExpressionMapping.MapperExtensions.<MapExpression>g__MapBody|8_1[TDestDelegate](Dictionary`2 typeMappings, XpressionMapperVisitor visitor, <>c__DisplayClass8_0`1& )
at AutoMapper.Extensions.ExpressionMapping.MapperExtensions.<MapExpression>g__CreateVisitor|8_0[TDestDelegate](Dictionary`2 typeMappings, <>c__DisplayClass8_0`1& )
at AutoMapper.Extensions.ExpressionMapping.MapperExtensions.MapExpression[TDestDelegate](IConfigurationProvider configurationProvider, LambdaExpression expression, Type typeSourceFunc, Type typeDestFunc, Func`3 getVisitor, Func`2 shouldConvertMappedBodyToDestType)
at AutoMapper.Extensions.ExpressionMapping.MapperExtensions.MapExpression[TDestDelegate](IMapper mapper, LambdaExpression expression, Func`3 getVisitor, Func`2 shouldConvertMappedBodyToDestType)
at AutoMapper.Extensions.ExpressionMapping.MapperExtensions.MapExpression[TDestDelegate](IMapper mapper, LambdaExpression expression)
I have created a simple reproduction repository:
https://github.com/yinzara/AutoMapper.Extensions.ExpressionMapping.bug-mapped-types
The expression mapper supports ForMember
, ForPath
and property maps. It does not support ConverUsing
. It also treats literals differently as you can see from #144 .
I think you may have hastily closed this before fully understanding it. The issue seems to be with structs specifically, not with ConvertUsing.
I've updated the example with more specifics that don't always use ConvertUsing
yet the bug still exists.
My test has the following cases of mapping property expressions from one entity to another:
Working Properly:
Map_Date_ToDate2 - object property to another object property that are convertible using CreateMap (not ConvertUsing) -> Succeed
Map_DateOnly_ToString - struct property to string property that are convertible using ConvertUsing -> Fails
Map_string_ToDate - string property to object property that are convertible using ConvertUsing -> Fails
Map_string_ToDateOnly - string property to struct property that are conertible using ConvertUsing -> Fails
Not Working as you describe:
Map_DateOnly_ToDate - struct property to another object property that are convertible using CreateMap (not ConvertUsing) -> Fails - this should succeed according to your above statement
Map_Date_ToString - object property to string property that are convertible using ConvertUsing -> Succeed - this should fail according to your above statement
Like I said this library treats literals differently. You can change these structures back and forth between struct and class without expression mapping errors for example. You'll find the tests use ForMember
rather than CreateMap
to convert literal types.
Consider trying to reproduce your failing case without literal types, ConvertUsings
etc..