我正在将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仅实现接口中指定的派生类型。
任何建议如何解决这个问题?
答案 0 :(得分:2)
好吧,这是不允许的,因为它的类型不安全。 ??以下内容为何不能安全输入:
var _handlers = new Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>>();
var loginRequestHandler = new LoginRequestHandler();
_handlers[messageId] = loginRequestHandler;
LoginRequestHandler
是IMessageHandler<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>
的变量,则可以使用HandleMessage
和IPeerAttachment
,从而导致运行时错误。