class MyClass<T> {
public event T MyEvent;
}
错误:CS0066 'MyClass<T>.MyEvent': event must be of a delegate type
。
好的…C#≥7.3 allows Delegate
as base class constraint。我们来使用它:
class MyClass<T> where T: Delegate {
public event T MyEvent;
}
错误:CS0066 'MyClass<T>.MyEvent': event must be of a delegate type
。
WTH ???
答案 0 :(得分:2)
尽管我在C#规范中找不到记录的限制,但我可以看到在C#/ CLR中支持此类事件至少有两个问题,都与引发它的方式有关。
C#仅允许从声明该事件的类型内引发事件。但是,如果您的通用类甚至不知道其T
的参数数量,引发事件的代码应该是什么样?
class MyClass<T> where T: Delegate
{
public event T MyEvent;
public void DoSomething()
{
// raise MyEvent here
MyEvent(/* what goes here? */);
}
}
当然,您可以使MyClass
抽象,并说指定T
类型的继承者将引发该事件。但是,我认为这将是一个非常不一致的语言设计。
CLR实现运行时泛型。这意味着,对于符合通用约束的任何T
,编译器必须生成在运行时应良好的IL。
引发事件基本上是调用存储在事件字段中的委托。编译器应生成大致包括以下步骤的IL:
如果委托人不是void
,则需要执行其他步骤:
如您所见,生成的IL严格取决于参数的数量以及委托是否为void
。因此,这样的IL对任何Delegate
都是不利的。
具有带有通用参数的事件委托完全可以,例如:
delegate void MyEventHandler<K, V>(K key, V value);
因为在编译时知道参数的数量以及委托是否为void
。在这种情况下,可以生成对任何K
和V
都适用的相同的IL指令集。在IL中,K
和V
被生成为类型占位符,CLR能够在运行时对其进行解析。