Autofac 和逆变:解析为更多派生类型
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>;
为什么上面的转换 returns 为空?即使在 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);
}
}
现在整个演员表都可以工作了,因为你的 classes 将明确实现 IMessageHandler<IMessage>
.
为了避免重复太多,你可以实现一个抽象class:
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
。
我正在编写通用消息处理程序,需要通过 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>;
为什么上面的转换 returns 为空?即使在 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);
}
}
现在整个演员表都可以工作了,因为你的 classes 将明确实现 IMessageHandler<IMessage>
.
为了避免重复太多,你可以实现一个抽象class:
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
。