如何让AutoMapper识别object实际类型并完成对应映射?
我有个Schedule类,里面的Event属性静态类型是object(类定义从XSD生成),但实际存的是Event的派生类实例,比如旧命名空间下的v1.Conference、v1.ReligiousCeremony这些。现在要用AutoMapper把旧命名空间的v1.Schedule映射到新命名空间的v2.Schedule,同时把对应的派生类也转成新命名空间的版本(比如v1.Conference转v2.Conference)。
但因为Schedule.Event的静态类型是object,AutoMapper没法自动识别它的实际类型并应用对应映射。目前我用的是手动判断类型再映射的写法:
var v2Schedule = mapper.Map<v2.Schedule>(v1Schedule); if (v2Schedule.Event is v1.Conference) { v2Schedule.Event = mapper.Map<v2.Conference>(v2Schedule.Event as v1.Conference); } if (v2Schedule.Event is v1.ReligiousCeremony) { v2Schedule.Event = mapper.Map<v2.ReligiousCeremony>(v2Schedule.Event as v1.ReligiousCeremony); }
(注:我知道C#7有类型switch语法,但现在还在用C#6)
不用写一堆if判断,你可以通过提前注册所有派生类的映射关系,再给Schedule的Event属性配置自定义映射逻辑,让AutoMapper自动识别实际类型完成映射。
1. 先注册所有派生类的映射
在AutoMapper的配置里,把旧命名空间的派生类和新命名空间对应的类一一映射:
var config = new MapperConfiguration(cfg => { // 先注册Schedule本身的映射 cfg.CreateMap<v1.Schedule, v2.Schedule>(); // 把所有Event派生类的映射都加上 cfg.CreateMap<v1.Conference, v2.Conference>(); cfg.CreateMap<v1.ReligiousCeremony, v2.ReligiousCeremony>(); // 其他派生类照着这个格式加就行 });
2. 给Schedule.Event配置自动映射逻辑
在Schedule的映射配置里,针对Event属性,用ResolveUsing让AutoMapper根据实际类型调用对应映射:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<v1.Schedule, v2.Schedule>() .ForMember(dest => dest.Event, opt => opt.ResolveUsing(src => { if (src.Event == null) return null; // 根据实际类型动态调用映射 return mapper.Map(src.Event, src.Event.GetType(), dest.Event.GetType()); })); // 别忘了注册派生类的映射 cfg.CreateMap<v1.Conference, v2.Conference>(); cfg.CreateMap<v1.ReligiousCeremony, v2.ReligiousCeremony>(); });
或者更简洁的写法,只要提前注册了派生类映射,直接用MapFrom处理:
cfg.CreateMap<v1.Schedule, v2.Schedule>() .ForMember(dest => dest.Event, opt => opt.MapFrom(src => src.Event != null ? mapper.Map(src.Event, src.Event.GetType(), typeof(object)) : null));
配置好之后,只需要一行代码就能完成全部映射:
var v2Schedule = mapper.Map<v2.Schedule>(v1Schedule);
AutoMapper会自动识别src.Event的实际类型,套用提前注册好的派生类映射,不用再手动写if判断了。
补充
如果你的AutoMapper版本支持,也可以用Include处理基类派生类的映射,但这里因为Event的静态类型是object,上面的自定义解析方式更直接好用。
内容的提问来源于stack exchange,提问作者Jason 'Bug' Fenter

