c# - 多个受约束的泛型类型的字典和接口
问题描述
我正在将 Java 项目转换为 C#,但遇到以下问题:
消息处理程序
public interface IMessageHandler<T, H> where T : IPeerAttachment where H : IMessage {
void HandleMessage(T clientAttachment, H message);
}
登录请求处理程序
public class LoginRequestHandler : IMessageHandler<LoginPeerAttachment , LoginRequest> {
public void HandleMessage(LoginPeerAttachment clientAttachment, LoginRequest message) {
}
}
消息处理程序注册表
private readonly Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>> _handlers = new Dictionary<MessageId, IMessageHandler<IPeerAttachment, IMessage>>();
我想做的是:
LoginRequestHandler loginRequestHandler = new LoginRequestHandler();
_handlers[messageId] = loginRequestHandler;
这给了我一个编译错误,告诉我它需要是 IMessageHandler 类型。
我不确定为什么这不起作用,因为 LoginRequestHandler 仅实现接口中指定的派生类型。
任何建议如何解决这个问题?
解决方案
好的,这是不允许的,因为它不是类型安全的。嗯?以下内容怎么可能不是类型安全的:
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
可以处理提供的参数类型...
所以,现在我们遇到了可怕的情况;遵循完全合法的步骤,我们刚刚破坏了类型系统,因为我们以某种方式要求 aLoginRequestHandler
处理 a LogOutRequest
。
显然,正如您亲身体验过的痛苦一样,并非所有步骤都是合法的。这种引用转换实际上是非法的:(IMessageHandler<IPeerAttachment, IMessage>)loginRequestHandler
为了使这种转换起作用, 的类型变化IMessageHandler
需要是协变的,这意味着,泛型参数只能出去,不能进来(它比这更令人费解,但它可以理解这个想法)。典型的例子?IEnumerable<out T>
? 为什么?因为无法T
在 an中输入 a IEnumerable<T>
,所以这是合法的:
var tigers = new List<Tiger>();
IEnumerable<Animal> animals = tigers;
但这不是:
var tigers = new List<Tiger>();
List<Animal> animals = tigers;
在您的场景中,协变接口似乎不是一种选择,因此您可能需要重新考虑您的方法。你似乎试图在你的类型系统中表达太多,以至于它与你作斗争。
推荐阅读
- php - 无停机 Laravel 部署
- regex - 没有在scala中正确拆分字符串
- python - 我刚刚创建了一个 Python 脚本。我正在尝试在我的 Windows 计算机上运行它。这没用
- python - 尝试在 Spyder (Python 3.7) 上安装新库
- javascript - React - 通过功能组件传递 props up 组件树
- angular - Angular 9 的交互式坐标系
- mysql - nodejs 服务器 app.post 问题 XML 解析错误:语法错误位置:http://localhost:3000/get_messages 第 1 行第 1 列:
- c# - WPF中切换用户控件只显示ViewModel的名称
- excel - 组合框列出路径中的最新 2 个文件夹
- r - 是否可以以水平和垂直显示总和的方式来 table() 两列?