【问题标题】:AutoMapAttribute with ReverseMap & TypeConverter to create 2-way maps?AutoMapAttribute 与 ReverseMap 和 TypeConverter 创建 2 路地图?
【发布时间】:2022-06-22 12:33:18
【问题描述】:

我有一个正在与之通信的设备。它以各种整数表示形式返回多个位标志(byteushortuint)。

目前,为了在 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 无论如何都会进行反射以找到属性;但是整个程序是使用基于属性的映射配置的,我更喜欢这些结构与代码库的其余部分一致

真的没有办法结合AutoMapAttributeReverseMapTypeConverter来创建2路地图吗?

注意:.NET6、AutoMapper 11.0

【问题讨论】:

  • 这里不需要ReverseMap,你可以简单地创建两个地图。
  • 我已经编辑了这个问题,以便更清楚地表明这是基于属性的配置。为了抢占“只注释另一个类”的建议,我将强调这适用于我无法控制的内置类型(byteuint 等)
  • 那你应该使用fluent API,attributes API只在最简单的情况下有用。

标签: c# .net automapper


【解决方案1】:

正如 cmets 中所述,这不是属性 API 所能做的。

我们最终通过简单地扫描整个程序集以查找ITypeConverter&lt;,&gt; 的所有实现并一一注册它们来自动化流畅的注册。

private static void CreateTypeConverterMaps(IMapperConfigurationExpression mapperCfg) {
  var converters = typeof(AType).Assembly
    .GetTypes()
    .SelectMany(typ => typ
      .GetInterfaces()
      .Where(itf => itf.IsGenericType)
      .Where(itf => itf.GetGenericTypeDefinition() == typeof(ITypeConverter<,>))
      .Select(itf => new { Interface = itf, Class = typ }));
  foreach (var conv in converters) {
    // We know there's two TypeArgs, as we filter by <,> above
    var srcType = conv.Interface.GenericTypeArguments[0];
    var dstType = conv.Interface.GenericTypeArguments[1];
    mapperCfg // Register the map+converter
      .CreateMap(srcType, dstType)
      .ConvertUsing(conv.Class);
  }
}

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多