【发布时间】:2022-06-22 12:33:18
【问题描述】:
我有一个正在与之通信的设备。它以各种整数表示形式返回多个位标志(byte、ushort、uint)。
目前,为了在 UI 上显示它们,它们被映射到 ViewModel:
// The ViewModel, annotated
[AutoMap(typeof(byte), TypeConverter = typeof(FlagConverter))]
public record FlagVM(bool One, bool Two)
{
// And its converter
public class FlagConverter : ITypeConverter<byte, FlagVM> {
public FlagVM Convert(byte src, FlagVM dst, ResolutionContext c)
=> new((src & 1) > 0, (src & 2) > 0);
}
使用AutoMapAttribute是因为有50多个其他结构,AutoMapper可以很容易地为整个Assembly配置:
var mapper = new MapperConfiguration(cfg =>
cfg.AddMaps(this.GetType().Assembly)
).CreateMapper();
mapper.Map<FlagVM>((byte)2)
.Should().Be(new FlagVM(false, true)); //easy!
现在,问题来了:我还需要创建反向映射,回到数字表示。很容易添加到转换器:
public class FlagConverter
: ITypeConverter<byte, FlagVM>, ITypeConverter<FlagVM, byte> {
public FlagVM Convert(byte src, FlagVM dst, ResolutionContext c)
=> new(One:(src & 1) > 0, Two:(src & 2) > 0);
public byte Convert(FlagVM src, byte dst, ResolutionContext c)
=> (byte)((src.One ? 1 : 0) | (src.Two ? 2 : 0));
}
这一切都很好,除了现在我不能再使用AutoMapAttribute,因为简单地添加ReverseMap 不起作用:
// The TypeConverter is not applied to the reverse map
[AutoMap(typeof(byte), TypeConverter = typeof(FlagConverter), ReverseMap = true)]
我可以获得双向映射的唯一方法是配置每一个(手动或反射)
var mapper = new MapperConfiguration(cfg =>
cfg.CreateMap<byte, FlagDto>().ConvertUsing<FlagConverter>();
cfg.CreateMap<FlagDto, byte>().ConvertUsing<FlagConverter>(); //reverse
// .. repeat 50+ times
// .. or use reflection to find all ITypeConverter<> implementations.
).CreateMapper();
// Forward map
mapper.Map<FlagVM>((byte)2).Should().Be(new FlagVM(false, true));
// Reverse map
mapper.Map<byte>(new FlagVM(false, true)).Should().Be(2);
是的,归根结底,AutoMapper 无论如何都会进行反射以找到属性;但是整个程序是使用基于属性的映射配置的,我更喜欢这些结构与代码库的其余部分一致。
真的没有办法结合AutoMapAttribute、ReverseMap和TypeConverter来创建2路地图吗?
注意:.NET6、AutoMapper 11.0
【问题讨论】:
-
这里不需要
ReverseMap,你可以简单地创建两个地图。 -
我已经编辑了这个问题,以便更清楚地表明这是基于属性的配置。为了抢占“只注释另一个类”的建议,我将强调这适用于我无法控制的内置类型(
byte,uint等) -
那你应该使用fluent API,attributes API只在最简单的情况下有用。
标签: c# .net automapper