我试图通过以下方式注册从基类派生的泛型,但得到错误:
无法将
类型MyCallback<T>
表达式转换为MyCallback<Event>
我希望限制会使这成为可能,但我错过了什么?
public class Event
{ };
public delegate void MyCallback<T>(T arg1) where T : Event;
static class EventDispatcher
{
public static Dictionary<string, MyCallback<Event>> eventTable = new Dictionary<string, MyCallback<Event>>();
static void RegisterCallback<T>(MyCallback<T> callback) where T : Event
{
eventTable.Add("test", callback);
}
}
答案 0 :(得分:0)
您需要将type参数作为EventDispatcher
类的一部分:
public class EventDispatcher<T> : where T : Event {
public Dictionary<string, MyCallback<T>> eventTable = new Dictionary<string, MyCallback<T>>();
void RegisterCallback(MyCallback<T> callback) {
eventTable.Add("test", callback);
}
}
这是因为MyCallback<Event>
中声明的eventTable
在编写时不会被编译为RegisteredCallback
中声明的相同类型。
答案 1 :(得分:0)
当你有一个MyCallback<Event>
时,你说你有一个可以采用任何类型的事件的方法。它可以接受EventOne
,EventTwo
或SomeOtherEvent
。
假设我调用RegisterCallback
并传入指向具有此签名的方法的委托:
public static void Foo(SomeOtherEvent arg)
如果您的代码可行,并且我可以将其分配给MyCallback<Event>
,那么我可以在调用它时将EventOne
实例传递给该方法。这显然是一个问题。
有一个术语;你希望MyCallback
是协变的关于它的泛型参数。事实上,它是逆变。如果我有一个方法可以接受任何类型的事件,我可以清楚地传入SomeEvent
或SomeOtherEvent
,这意味着我可以指定MyCallback<Event>
到MyCallback<SomeOtherEvent>
,而不是相反。
如果你想告诉编译器,“我知道这个方法实际上不能用任何类型的事件调用,但我希望你允许这个检查,只有在给定的参数不合适时才会在运行时失败类型。”然后你可以这样做,假设你确实有办法确保用适当的参数调用每个回调。你不能只是做演员;你需要将方法包装在一个执行强制转换的新方法中:
eventTable.Add("test", e => callback((T)e));