简体   繁体   中英

Using parameter of generic class as type of event

class MyClass<T> {
    public event T MyEvent;
}

Error: CS0066 'MyClass<T>.MyEvent': event must be of a delegate type .

Okay… C# ≥7.3 allows Delegate as base class constraint . Let's use that:

class MyClass<T> where T: Delegate {
    public event T MyEvent;
}

Error: CS0066 'MyClass<T>.MyEvent': event must be of a delegate type .

WTH???

Though I can't find a documented limitation in the C# spec, I can see at least two problems with supporting such an event in C#/CLR, both related to how it is raised.

First difficulty: in the language

C# only allows raising an event from within the type that declares it. But if your generic class doesn't even know the number of parameters it T , what should the code that raises the event look like?

class MyClass<T> where T: Delegate 
{
    public event T MyEvent;

    public void DoSomething()
    {
        // raise MyEvent here
        MyEvent(/* what goes here? */);
    }
}

Of course, you can make MyClass abstract and say that inheritors that specify the type of T would raise the event. However, this would be quite an inconsistent language design, to my opinion.

Second difficulty: in the compiler

CLR implements runtime generics. This means, that compiler must generate IL that should be good at runtime for any T that meets the generic constraints.

Raising an event is basically invoking a delegate that's stored in the event field. The compiler should generate IL that roughly includes these steps:

  • push delegate object reference onto the stack
  • push argument 1
  • push argument 2
  • ....
  • push argument N
  • call delegate's Invoke method

If the delegate isn't void , an additional step is required:

  • pop return value from the stack and possibly store it in a field or a local variable

As you can see, the generated IL strictly depends on the number of arguments and whether the delegate is void . Therefore, such IL cannot be good for any Delegate .

In contrast

Having event delegate with generic parameters is perfectly OK, such as:

delegate void MyEventHandler<K, V>(K key, V value);

because the number of the parameters and whether the delegate is void is known at compile time. In this case the same set of IL instructions can be generated that is good for any K and V . In the IL, K and V are generated as type placeholders, which CLR is capable of resolving at runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM