【问题标题】:Inferring destination type from interface with AutoMapper从与 AutoMapper 的接口推断目标类型
【发布时间】:2017-08-11 11:48:29
【问题描述】:

我正在尝试在我的应用程序中实现一些横切关注点,它使用 AutoMapper 在不同的 DTO/消息对象之间进行映射。

假设我有这个: configuration.Map<MyMessage, MyEvent>()MyEvent 实现 IEvent(这是一个没有属性的标记接口)。有没有办法让 AutoMapper 将MyMessage 映射到IEvent,并让它推断“哦,我有一个映射MyMessageMyEvent,而MyEvent 实现IEvent”?

这个(无效的)示例显示了我想要实现的目标:

// IEvent is just a marker interface with no properties,
// and is implemented by all of the *Event classes

configuration.CreateMap<MyMessage, MyEvent>();
configuration.CreateMap<MyOtherMessage, MyOtherEvent>();
// etc.

// ... somewhere else in the code ...

public class MyCrossCuttingThing<TMessage>
{
    private readonly IMapper _mapper;

    // ... code that does stuff ...

    public void DoThing(TMessage message)
    {
        // ... more code ...

        var @event = _mapper.Map<IEvent>(message);

        // Here I would expect @event to be a MyEvent instance if
        // TMessage is MyMessage, for example
    }
}

这给了我一个例外:

缺少类型映射配置或不支持的映射。

我尝试将.Include.IncludeBase 添加到CreateMap 语句,但结果相同。有什么方法可以实现我想要的,或者这根本不是一个受支持的用例?

【问题讨论】:

  • 出于兴趣,会不会让你写configuration.Map&lt;MyMessage, IEvent&gt;();
  • 不,IEvent 只是一个标记接口,没有可以映射到的属性。如果我尝试映射到它,AutoMapper 只会生成一个 Proxy&lt;&gt; 实例,我不能使用它,因为我想在映射后序列化事件。
  • 好的。你说 - “它推断“哦,我有一个映射 MyMessage 到 MyEvent,而 MyEvent 实现了 IEvent”。我原以为,当你有多个实现 IEvent 的映射时,这个问题就会出现,例如 @ 987654337@ 其中 MyEvent2 也实现了 IEvent。因此,我怀疑该工具不会设置为执行此操作,因为在我刚刚描述的情况下,它不知道映射到什么。这只是我最好的猜测为什么它不会不行。
  • 但是由于您希望@event 应该是一个 MyEvent 实例,所以不清楚为什么不能直接映射到它?例如var @event = _mapper.Map&lt;MyEvent&gt;(message);。也许我在您对场景的解释中遗漏了一些关于您为什么不能/不想这样做的内容。
  • @ADyson - 这只是一个假设,但我想他可能有多个实现相同接口的类,并且想要创建一个始终返回一个接口的通用方法,该接口以后可以转换为一个具体的类。

标签: c# automapper


【解决方案1】:

对于这种简单的情况,您可以使用 As。

CreateMap<MyMessage, IEvent>().As<MyEvent>();

鉴于IEvent 是一个标记接口,您还需要具体映射MyMessage=>MyEvent。 如果您的实际情况更复杂,您需要Includedocs

【讨论】:

  • 只是为了扩展这个答案,确保有具体的映射 - 即 CreateMap();陈述。否则,它仍然会给你映射不支持的错误。
  • 是的。它不会崩溃,但也不起作用:)(最新版本)。也许这里有一个错误。
  • 我错了。我正在使用基类进行测试。它适用于没有具体地图的界面。
  • 您能否更新您的问题,仅提及对您有用的方法?因为,当我尝试时,如果没有具体的地图,我无法获得所需的输出。
  • 那么你毕竟还需要具体的地图:)
【解决方案2】:

我找到了实现我想要的方法:

configuration.CreateMap<MyMessage, MyEvent>();
configuration.CreateMap<MyMessage, IEvent>()
    .ConstructUsing((m, c) => c.Mapper.Map<MyMessage, MyEvent>(m));

configuration.CreateMap<MyOtherMessage, MyOtherEvent>();
configuration.CreateMap<MyOtherMessage, IEvent>()
    .ConstructUsing((m, c) => c.Mapper.Map<MyOtherMessage, MyOtherEvent>(m));

// etc. - will encapsulate in an extension method

通过像这样注册映射,AutoMapper 根据TMessage 类型找到正确的映射器,并返回一个事件实例。就像我希望的那样简单!

【讨论】:

  • As 就是这样 :) 你刚刚用 hack 重新实现了它。
  • 是的,我尝试使用 As,但它实际上并没有映射任何东西 - 可能是因为 IEvent 在“真实”映射中没有任何属性。我假设如果IEvent 接口也具有映射属性,As 会按预期工作?
  • 我测试过,它可以工作。而不是 ConstructUsing 你把 As。你用的是旧版本吗?它当然适用于最新版本。
  • 哦!我在 .NET 4.5.2 上使用 AutoMapper 6.1.1 进行了尝试:CreateMapper&lt;MyMessage, IEvent&gt;().As&lt;MyEvent&gt;() 然后Map&lt;IEvent&gt;(message) 其中messageMyMessage 实例,但返回对象上的所有属性都是空的。是否需要更多设置?
  • ...我可能很厚,我还没有像你现在的回答那样添加具体的地图。回家后我会验证,但您可能是对的 - 我重新发明了轮子,因为我没有足够好地阅读文档。
猜你喜欢
  • 2019-06-27
  • 1970-01-01
  • 1970-01-01
  • 2022-11-24
  • 2014-05-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-31
  • 2017-11-19
相关资源
最近更新 更多