3

我正在使用 MEF(特别是MEF 2 Preview 5)开发应用程序,并且在尝试基于通用接口导入时遇到了问题。

我有一个界面:

public interface IMessageHandler<in T>
{
    void HandleMessage(T message);
}

其中 T 是要处理的消息类型。我正在使用以下方法将这些东西导入目录RegistrationBuilder

RegistrationBuilder context = new RegistrationBuilder();

context.ForTypesDerivedFrom(typeof(IMessageHandler<>))
    .Export(builder => builder.AsContractType(typeof(IMessageHandler<>)));

然后,在我[ImportMany]用来将这些列表导入到的消费类中IEnumerable<Lazy>>

[ImportMany(typeof(IMessageHandler<>))]
IEnumerable<Lazy<IMessageHandler<object>, HandledMessageTypeAttribute>> _messageHandlers;

现在,这是第一个问题——此时您被迫为泛型接口分配一个类型。我正在使用Lazy<T, TMetadata>,因为IMessageHandler<T>实现具有我想要使用的相关元数据(HandledMessageTypeAttribute)。

现在,当我想访问IEnumerable<Lazy<>>集合中的任何元素时,我得到以下异常:

Cannot cast the underlying exported value of type 
'MessageHandlerImplementation (ContractName="IMessageHandler(System.Object)")' 
to type 'IMessageHandler`1[System.Object]'.

我(大致)理解为什么我会遇到异常,问题是我不知道如何解决它。所以,基本上我想做的是:

  1. 有一堆实现IMessageHandler<T>接口的类。
  2. 使用 MEF 在运行时发现它们。
  3. 将它们导入到一个集合中,这样我就可以使用它们拥有的任何元数据。
  4. 能够实例化它们。

我知道我可以简单地制作IMessageHandler非泛型并IMessageHandler.HandleMessage()接受类型参数,object但我正在寻找一个更优雅的解决方案

任何指针或指导表示赞赏。

4

1 回答 1

3

在不使用非通用接口的情况下,我没有看到更好的方法来完成您想要实现的目标。问题的根源在于接口的定义:

public interface IMessageHandler<in T>

这意味着如果我们有两个类,A并且B,其中B派生自A,那么这是允许的

IMessageHandler<B> handler = new AHandler();

但这不是:

IMessageHandler<A> handler = new BHandler();

您实际上是在尝试执行后者,这就是引发异常的原因。我假设你想做的是能够得到一个处理程序,给定一个类型。如果是这种情况,那么您可能应该使用非通用接口并在导出元数据中提供消息类型。然后你会有这样的东西:

public IMessageHandler GetHandler<T>()
{
    Type handlerType = typeof(T);
    return _messageHandlers.FirstOrDefault(x => x.Metadata.MessageType == handlerType);
}

您可能会发现这个问题也很相关。希望这可以帮助。

于 2012-06-21T20:45:20.277 回答