我正在使用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]'.
我理解(粗略地)为什么我得到了例外,问题是我不知道如何绕过它。所以,基本上我想做的是:
IMessageHandler<T>
接口的类。我知道我可以简单地使IMessageHandler
非通用,让IMessageHandler.HandleMessage()
接受object
类型的参数,但我正在寻找更优雅的解决方案
赞赏任何指示或指导。
答案 0 :(得分: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);
}
您也可能会发现this question相关。希望这会有所帮助。