使用AutoMapper映射含ImmutableList的类型时出错,如何解决?
问题场景
源类ClassSource包含IEnumerable<int>类型的Nums属性,目标类ClassDestination通过构造函数接收IEnumerable<int>参数,将其转换为IImmutableList<int>后赋值给自身的IEnumerable<int>类型Nums属性。在.NET 7.0环境下,当源数据的Nums通过ToList()生成时映射正常,但用ToImmutableList()生成时会抛出AutoMapper.AutoMapperMappingException异常。
问题根源
AutoMapper默认的构造函数参数解析逻辑对不可变集合类型(如IImmutableList)的类型匹配存在缺陷:当源集合是ImmutableList实例时,AutoMapper无法自动完成IEnumerable<int>到IImmutableList<int>的隐式转换绑定,导致构造函数参数匹配失败,触发异常。
可行解决方案
1. 显式指定目标类实例化逻辑
在AutoMapper配置中,使用ConstructUsing手动控制目标对象的创建过程,绕过AutoMapper自带的构造函数解析逻辑:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<ClassSource, ClassDestination>() .ConstructUsing(src => new ClassDestination(src.Nums)); }); var mapper = config.CreateMapper();
这种方式直接告诉AutoMapper如何从源对象生成目标对象,完全避免了类型匹配问题。
2. 注册全局类型转换器
为AutoMapper添加IEnumerable<int>到IImmutableList<int>的类型转换规则,让框架知道如何处理这种类型转换:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<IEnumerable<int>, IImmutableList<int>>() .ConvertUsing(input => input.ToImmutableList()); cfg.CreateMap<ClassSource, ClassDestination>(); });
配置后,AutoMapper在处理构造函数参数或属性映射时,会自动使用该转换器完成类型转换。
3. 升级AutoMapper版本
确保使用AutoMapper 12.x及以上版本,旧版本对.NET 7的不可变集合支持不完善,升级后可能自动修复类型匹配问题。
4. 调整目标类构造函数参数类型(可选)
如果业务允许,可将目标类的构造函数参数改为IImmutableList<int>,并在映射配置中显式转换源属性:
// 修改目标类 public class ClassDestination { public IEnumerable<int> Nums { get; } public ClassDestination(IImmutableList<int> nums) { Nums = nums; } } // 配置映射 var config = new MapperConfiguration(cfg => { cfg.CreateMap<ClassSource, ClassDestination>() .ForMember(dest => dest.Nums, opt => opt.MapFrom(src => src.Nums.ToImmutableList())); });
这种方式更直接,但需要修改目标类的定义。
内容的提问来源于stack exchange,提问作者teenboy

