1

我正在编写一个通用消息处理程序,需要通过 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<>接口中定义了逆变。

如何解决适当的处理程序?

谢谢

4

1 回答 1

3

哎呀!

// 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)
    {
        // ...
    }
}

也就是说,你的演员可以变成 just handler as IMessageHandler

于 2016-11-06T10:54:03.940 回答