Automapper派生类型属性未赋值问题排查求助
为什么AutoMapper映射后
NumberOfLines属性变为默认值? 问题重现
我尝试将MyGenericResponseObject<OrderSummaryViewModel>类型的对象映射到MyResponseObject,预期两个对象的Items列表内容完全一致,但实际映射后NumberOfLines属性变成了默认值0。使用环境为.NET6及最新稳定版AutoMapper。
代码示例
using System; using System.Collections.Generic; using AutoMapper; public class OrderViewModel { public Guid Id {get;set;} } public class OrderSummaryViewModel : OrderViewModel { public int NumberOfLines {get;set;} } public class MyGenericResponseObject<T> { public List<T> Items {get;set;} = new(); } public class MyResponseObject : MyGenericResponseObject<OrderSummaryViewModel> { } public class Program { public static void Main() { var e1 = new MyGenericResponseObject<OrderSummaryViewModel> { Items = new() { new() { Id = Guid.NewGuid(), NumberOfLines = 420 } } }; var config = new MapperConfiguration(cfg => { cfg.CreateMap<OrderSummaryViewModel, OrderViewModel>(); cfg.CreateMap<OrderViewModel, OrderSummaryViewModel>(); cfg.CreateMap<MyGenericResponseObject<OrderSummaryViewModel>, MyResponseObject>(); }); var mapper = config.CreateMapper(); var e2 = mapper.Map<MyGenericResponseObject<OrderSummaryViewModel>, MyResponseObject>(e1); foreach (var i in e1.Items) { Console.WriteLine($"{i.Id} - {i.NumberOfLines}"); } Console.WriteLine("------------------"); foreach (var i in e2.Items) { Console.WriteLine($"{i.Id} - {i.NumberOfLines}"); } } }
实际输出
701cde6c-4751-4419-a2cb-1d347a3eb0e6 - 420 ------------------ 701cde6c-4751-4419-a2cb-1d347a3eb0e6 - 0
补充测试结果
配置1:移除OrderSummaryViewModel -> OrderViewModel映射
var config = new MapperConfiguration(cfg => { //cfg.CreateMap<OrderSummaryViewModel, OrderViewModel>(); cfg.CreateMap<OrderViewModel, OrderSummaryViewModel>(); cfg.CreateMap<MyGenericResponseObject<OrderSummaryViewModel>, MyResponseObject>(); });
输出:
1d31bf14-0bf2-4a10-8c4d-92efa9d6e131 - 420 ------------------ 1d31bf14-0bf2-4a10-8c4d-92efa9d6e131 - 0
配置2:移除OrderViewModel -> OrderSummaryViewModel映射
var config = new MapperConfiguration(cfg => { cfg.CreateMap<OrderSummaryViewModel, OrderViewModel>(); //cfg.CreateMap<OrderViewModel, OrderSummaryViewModel>(); cfg.CreateMap<MyGenericResponseObject<OrderSummaryViewModel>, MyResponseObject>(); });
输出(报错):
Unhandled exception. System.ArgumentException: Expression of type 'OrderViewModel' cannot be used for parameter of type 'OrderSummaryViewModel' of method 'Void Add(OrderSummaryViewModel)' (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) at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments) at AutoMapper.Internal.Mappers.CollectionMapper.<MapExpression>g__MapCollectionCore|2_1(Expression destExpression, <>c__DisplayClass2_0& ) at AutoMapper.Internal.Mappers.CollectionMapper.MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) at AutoMapper.Execution.ExpressionBuilder.MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, TypePair typePair, Expression source, MemberMap memberMap, Expression destination) at AutoMapper.Execution.TypeMapPlanBuilder.MapMember(MemberMap memberMap, Expression destinationMemberValue, ParameterExpression resolvedValue) at AutoMapper.Execution.TypeMapPlanBuilder.CreatePropertyMapFunc(MemberMap memberMap, Expression destination, MemberInfo destinationMember) 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 AutoMapper.MapperConfiguration..ctor(Action`1 configure) at Program.Main() Command terminated by signal 6
配置3:移除两个类型的双向映射
var config = new MapperConfiguration(cfg => { //cfg.CreateMap<OrderSummaryViewModel, OrderViewModel>(); //cfg.CreateMap<OrderViewModel, OrderSummaryViewModel>(); cfg.CreateMap<MyGenericResponseObject<OrderSummaryViewModel>, MyResponseObject>(); });
输出(符合预期):
d9e72e9e-9bc0-41fb-bf4d-33242dca5027 - 420 ------------------ d9e72e9e-9bc0-41fb-bf4d-33242dca5027 - 420
原因分析
问题出在显式配置的OrderViewModel与OrderSummaryViewModel之间的双向映射:
- AutoMapper处理集合映射时,会检查元素类型的映射规则。虽然源和目标集合的元素类型都是
OrderSummaryViewModel,但由于配置了该类型与父类OrderViewModel的映射,AutoMapper会错误触发类型转换逻辑。 - 具体流程为:将
OrderSummaryViewModel先映射为OrderViewModel(丢失子类独有的NumberOfLines属性),再尝试映射回OrderSummaryViewModel,此时NumberOfLines会被初始化为默认值0。 - 移除这两个映射配置后,AutoMapper会使用默认的同类型映射逻辑,直接复制所有属性,结果符合预期。
解决方案
- 如果不需要
OrderViewModel与OrderSummaryViewModel之间的映射,直接移除这两个CreateMap配置即可。 - 如果确实需要这两个类型的映射,需显式指定同类型的映射规则,确保AutoMapper优先使用同类型复制:
或者在配置集合映射时明确指定使用同类型映射,避免触发父类子类的转换逻辑。cfg.CreateMap<OrderSummaryViewModel, OrderSummaryViewModel>().ReverseMap();
内容的提问来源于stack exchange,提问作者sommmen
相关产品推荐
相关产品推荐

