[英]Autofac and contravariance : resolving to more derived type
我正在編寫通用消息處理程序,需要通過AutoFac獲取各種消息處理程序。 消息處理程序的基本定義是:
public interface IMessageHandler<in TMessage> :
IMessageHandler
where TMessage : IMessage
{
Task<IMessageResult> Handle(TMessage message);
}
我還定義了一個標記器接口,以便可以在AutoFac中輕松注冊它們
public interface IMessageHandler
{
}
樣本消息處理程序為:
public class CreatedEventHandler : IMessageHandler<CreatedEvent>
{
public Task<IMessageResult> Handle(CreatedEvent message)
{
// ...
}
}
這些都通過Autofac使用以下方式很好地注冊了
builder.RegisterAssemblyTypes(assemblies)
.Where(t => typeof(IMessageHandler).IsAssignableFrom(t))
.Named<IMessageHandler>(t => t.Name.Replace("Handler", string.Empty))
.InstancePerLifetimeScope();
這一切都很好。 但是,當我需要解決處理程序時,我遇到了一個問題
// handler returned is non null and of type marker interface IMessageHandler
var handler = container.Resolve("CreatedEvent");
// This is null. I just can't understand why
var createdEventHander = handler as IMessageHandler<IMessage>;
為什么上面的轉換返回null? 即使在IMessageHandler<>
接口中定義了IMessageHandler<>
。
如何解決適當的處理程序?
謝謝
糟糕!
// Covariance
handler as IMessageHandler<IMessage>;
您的handler
具有一個不是IMessage
而是IMessage
實現的通用參數。 因此,這就是協方差 (您正在泛化一個通用參數)。
由於我不知道您的實際軟件架構,因此無法為您提供解決方案。 至少,您知道為什么整個轉換都為null
。
您的消息處理程序都可以實現IMessageHandler<ConcreteEvent>
和新的非通用接口IMessageHandler
:
public interface IMessageHandler
{
Task<IMessageResult> Handle(IMessage message);
}
public interface IMessageHandler<TMessage> : IMessageHandler
where TMessage : IMessage
{
Task<IMessageResult> Handle(TMessage message);
}
public class CreatedEventHandler : IMessageHandler<CreatedEvent>
{
public Task<IMessageResult> Handle(CreatedEvent message)
{
// ...
}
// I would implement the non-generic Handle(IMessage) explicitly
// to hide it from the public surface. You'll access it when successfully
// casting a reference to IMessageHandler
Task<IMessageResult> IMessageHandler.Handle(IMessage message)
{
return Handle((CreatedEvent)message);
}
}
現在,整個轉換將起作用,因為您的類將顯式實現IMessageHandler<IMessage>
。
為了避免重復太多,可以實現一個抽象類:
public abstract class MessageHandler<TMessage> : IMessageHandler<TMessage>
where TMessage : IMessage
{
public abstract Task<IMessageResult> Handle(TMessage message);
// I would implement the non-generic Handle(IMessage) explicitly
// to hide it from the public surface. You'll access it when successfully
// casting a reference to IMessageHandler
Task<IMessageResult> IMessageHandler.Handle(IMessage message)
{
return Handle((TMessage)message);
}
}
最后,您的具體消息處理程序將如下所示:
public class CreatedEventHandler : MessageHandler<CreatedEvent>
{
public Task<IMessageResult> Handle(CreatedEvent message)
{
// ...
}
}
也就是說,可以將您的類型轉換僅handler as IMessageHandler
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.