C# Autofac和逆变:解析为更多派生类型

C# Autofac和逆变:解析为更多派生类型,c#,dependency-injection,autofac,contravariance,marker-interfaces,C#,Dependency Injection,Autofac,Contravariance,Marker Interfaces,我正在编写一个通用消息处理程序,需要通过AutoFac获得各种消息处理程序。消息处理程序的基本定义是: public interface IMessageHandler<in TMessage> : IMessageHandler where TMessage : IMessage { Task<IMessageResult> Handle(TMessage message); } public class CreatedEventHandler

我正在编写一个通用消息处理程序,需要通过AutoFac获得各种消息处理程序。消息处理程序的基本定义是:

public interface IMessageHandler<in TMessage> :
    IMessageHandler
    where TMessage : IMessage
{
    Task<IMessageResult> Handle(TMessage message);
}
public class CreatedEventHandler : IMessageHandler<CreatedEvent>
{
    public Task<IMessageResult> Handle(CreatedEvent message)
    {
        // ...
    }
}
示例消息处理程序是:

public interface IMessageHandler<in TMessage> :
    IMessageHandler
    where TMessage : IMessage
{
    Task<IMessageResult> Handle(TMessage message);
}
public class CreatedEventHandler : IMessageHandler<CreatedEvent>
{
    public Task<IMessageResult> Handle(CreatedEvent message)
    {
        // ...
    }
}
public类CreatedEventHandler:IMessageHandler
{
公共任务句柄(CreatedEvent消息)
{
// ...
}
}
通过Autofac使用

builder.RegisterAssemblyTypes(assemblies)
       .Where(t => typeof(IMessageHandler).IsAssignableFrom(t))
       .Named<IMessageHandler>(t => t.Name.Replace("Handler", string.Empty))
       .InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(程序集)
.Where(t=>typeof(IMessageHandler).IsAssignableFrom(t))
.Named(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
var handler=container.Resolve(“CreatedEvent”);
//这是空的。我就是不明白为什么
var createdEventHander=作为IMessageHandler的处理程序;
为什么上面的强制转换返回空值?即使在
IMessageHandler
界面中定义了对冲

如何解析适当的处理程序

谢谢

哎呀

// Covariance
handler as IMessageHandler<IMessage>;
现在整个cast都可以工作了,因为您的类将显式实现
IMessageHandler

为了避免重复太多,您可以实现一个抽象类:

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);
        }
}
公共抽象类MessageHandler:IMessageHandler
where-TMessage:IMessage
{
公共抽象任务句柄(TMessage消息);
//我将显式地实现非泛型句柄(IMessage)
//从公共界面隐藏它。成功后您将访问它
//强制转换对IMessageHandler的引用
任务IMessageHandler.Handle(IMessage消息)
{
返回句柄((TMessage)消息);
}
}
最后,您的具体消息处理程序如下所示:

public class CreatedEventHandler : MessageHandler<CreatedEvent>
{
    public Task<IMessageResult> Handle(CreatedEvent message)
    {
        // ...
    }
}
public类CreatedEventHandler:MessageHandler
{
公共任务句柄(CreatedEvent消息)
{
// ...
}
}

也就是说,您的cast可以作为IMessageHandler转换为
处理程序,这看起来是一个优雅的解决方案。但是,我在MessageHandler抽象类上遇到一个编译错误:“MessageHandler”不能同时实现“IMessageHandler”和“IMessageHandler”,因为它们可能会为某些类型参数统一substitutions@sppc42嗯,你说得对。现在我已经放弃了那部分。稍后我将使用修复程序编辑我的答案;)@sppc42检查我的编辑答案。现在,我引入了一个非通用接口来满足我们无法用我以前的答案文本实现的相同要求。@sppc42没问题,欢迎您!我很高兴它在您的场景中运行良好。我现在担心的是它是否只是一个设计缺陷上的补丁,还是在您的场景中是正确的解决方案。这一考虑现在取决于你了!;)这与Autofac无关。这就是C#/CLR中方差的工作原理。