如何在AutoMapper中创建带成员复杂映射的泛型映射
解决AutoMapper泛型映射中截断列表的问题
你遇到的错误是因为泛型映射的非泛型写法里,lambda的src参数被推断为object类型,编译器找不到Items属性。要把具体类型的映射逻辑复用在泛型映射上,有两种可行方案:
方案1:定义通用接口(推荐)
先给ResponseModels<T>和ResponseDTOs<T>定义一个通用接口,统一成员访问方式:
public interface IPaginatedResponse<T> { IEnumerable<T> Items { get; set; } int TotalCount { get; set; } } // 让你的模型类实现这个接口 public class ResponseModels<T> : IPaginatedResponse<T> { public IEnumerable<T> Items { get; set; } public int TotalCount { get; set; } } public class ResponseDTOs<T> : IPaginatedResponse<T> { public IEnumerable<T> Items { get; set; } public int TotalCount { get; set; } }
然后用这个接口来编写泛型映射逻辑,这样就能在lambda里强转src为接口类型,直接访问Items:
int MaxOutListLength = 10; // 假设你的上限值 CreateMap(typeof(ResponseModels<>), typeof(ResponseDTOs<>)) .ForMember("Items", opt => opt.MapFrom((src, _, __, ___) => { var response = (IPaginatedResponse<object>)src; return response.Items.Take(MaxOutListLength); })) .ForMember("TotalCount", opt => opt.MapFrom((src, _, __, ___) => { var response = (IPaginatedResponse<object>)src; var itemCount = response.Items.Count(); return itemCount > MaxOutListLength ? MaxOutListLength : itemCount; }));
方案2:用反射访问成员(无需修改模型)
如果不想给模型加接口,可以通过反射获取Items属性的值:
int MaxOutListLength = 10; CreateMap(typeof(ResponseModels<>), typeof(ResponseDTOs<>)) .ForMember("Items", opt => opt.MapFrom((src, _, __, ___) => { var itemsProp = src.GetType().GetProperty(nameof(ResponseModels<object>.Items)); var items = (IEnumerable<object>)itemsProp.GetValue(src); return items.Take(MaxOutListLength); })) .ForMember("TotalCount", opt => opt.MapFrom((src, _, __, ___) => { var itemsProp = src.GetType().GetProperty(nameof(ResponseModels<object>.Items)); var items = (IEnumerable<object>)itemsProp.GetValue(src); var itemCount = items.Count(); return itemCount > MaxOutListLength ? MaxOutListLength : itemCount; }));
原理说明
- 具体类型的映射写法中,
src是明确的ResponseModels<Order>类型,所以能直接访问Items; - 泛型非泛型写法中,
src默认是object类型,必须通过接口强转或者反射来获取属性值,避免编译错误。
内容的提问来源于stack exchange,提问作者VovaLeder
相关产品推荐
相关产品推荐

