多种约束泛型类型的字典和接口

时间:2018-10-28 10:47:44

标签: c# dictionary generics interface

我正在将Java项目转换为C#,并且遇到以下问题:

IMessageHandler

 public interface IMessageHandler<T, H> where T : IPeerAttachment where H : IMessage {
    void HandleMessage(T clientAttachment, H message);
}

LoginRequestHandler

public class LoginRequestHandler : IMessageHandler<LoginPeerAttachment , LoginRequest> {
    public void HandleMessage(LoginPeerAttachment clientAttachment, LoginRequest message) {

    }
}

MessageHandlerRegistry

 private readonly Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>> _handlers = new Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>>();

我想做的是:

LoginRequestHandler loginRequestHandler = new LoginRequestHandler();
_handlers[messageId] = loginRequestHandler;

这给了我一个编译错误,告诉我它必须是IMessageHandler类型。

我不确定为什么这不起作用,因为LoginRequestHandler仅实现接口中指定的派生类型。

任何建议如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

好吧,这是不允许的,因为它的类型不安全。 ??以下内容为何不能安全输入:

var _handlers = new Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>>();
var loginRequestHandler = new LoginRequestHandler();
_handlers[messageId] = loginRequestHandler;

LoginRequestHandlerIMessageHandler<IPeerAttachment, IMessage>,所以这里出了什么问题?

好吧,假设前者是合法的,然后再往前走一步,看看会发生什么:

var handler = _handlers[meesageId];
handler.HandleMessage(logOutPeerAttachment, logOutMessage);

那合法吗?好吧,看起来确实像这样。 handler的类型为IMessageHandler<IPeerAttachment, IMessage>,因此HandleMessage可以处理提供的参数类型...

所以,现在我们进入了一个可怕的境地。遵循完全合法的步骤,我们刚刚破坏了类型系统,因为以某种方式要求LoginRequestHandler处理LogOutRequest

很显然,由于您亲身经历了第一手痛苦,因此并非所有步骤都是合法的。该引用转换实际上是非法的:(IMessageHandler<IPeerAttachment, IMessage>)loginRequestHandler

要使此转换正常进行,IMessageHandler的类型方差必须是协变的,这意味着通用参数只能输出,而不能输入(它比这更复杂,但是可以理解)跨)。规范的例子? IEnumerable<out T>?为什么?由于无法在T中输入IEnumerable<T>,因此这是合法的:

var tigers = new List<Tiger>();
IEnumerable<Animal> animals = tigers;

但这不是:

var tigers = new List<Tiger>();
List<Animal> animals = tigers;

在您的方案中,协变接口似乎不是一个选择,因此您可能需要重新考虑您的方法。您似乎试图在类型系统中表达过多的内容,以至于它与您抗争。

答案 1 :(得分:1)

您要尝试做的事情基本上与类型系统不兼容,而对于像Java类型系统这样的泛型变数而言,这种类型系统并不是不够完善。

如果您可以将LoginRequestHandler分配给类型IMessageHandler<IPeerAttachment, IMessage>的变量,则可以使用HandleMessageIPeerAttachment,从而导致运行时错误。