源类含Original属性且目标为record时,AutoMapper为何抛出NullReferenceException?
为何AutoMapper在源类含
Original属性且目标为record时抛出NullReferenceException? 问题重现
你提供的代码运行时会触发NullReferenceException,但修改源属性名或把目标改为普通类后即可正常运行:
using AutoMapper; var mapper = new MapperConfiguration(conf => { conf.CreateMap<From, To>(); }).CreateMapper(); var from = new From(); var to = mapper.Map<To>(from); public class From { public string? Original { get; set; } public bool BoolProp { get; set; } } public record To { public bool BoolProp { get; init; } }
原因分析
这是AutoMapper处理record类型的特殊逻辑与C# record的编译器生成代码冲突导致的:
- C# record编译时会自动生成隐藏的克隆构造函数,其中包含一个名为
Original的参数,类型为当前record类型(此处为To),用于支持With方法的实例克隆功能。 - AutoMapper的成员匹配逻辑会匹配名称相同的成员,无论其可见性(哪怕是编译器生成的隐藏成员)。它会误将源类的
string? Original属性,与目标record的隐藏To Original参数关联映射。 - 当源类的
Original属性值为null时,AutoMapper尝试将null赋值给类型为To的参数,在内部反射处理过程中触发NullReferenceException。
两种规避场景的原理:
- 修改源属性名:源属性名不再与record隐藏的
Original参数重名,AutoMapper不会进行错误匹配。 - 目标改为普通类:普通类没有编译器生成的隐藏
Original克隆参数,AutoMapper只会映射双方显式定义的同名属性(此处只有BoolProp)。
解决方法
你可以通过以下任意一种方式解决问题:
- 修改源属性名:避免使用
Original这类会与record隐藏成员冲突的名称。 - 显式指定映射成员:在AutoMapper配置中明确只映射目标record中存在的属性,避免AutoMapper尝试匹配隐藏成员:
var mapper = new MapperConfiguration(conf => { conf.CreateMap<From, To>() .ForMember(dest => dest.BoolProp, opt => opt.MapFrom(src => src.BoolProp)); }).CreateMapper();
- 忽略未匹配的成员:配置AutoMapper忽略目标中不存在的显式成员(间接避免匹配隐藏成员):
var mapper = new MapperConfiguration(conf => { conf.CreateMap<From, To>() .ForAllOtherMembers(opt => opt.Ignore()); }).CreateMapper();
内容的提问来源于stack exchange,提问作者Rowan Freeman
相关产品推荐
相关产品推荐

