Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I just use EventHandler<int> instead of deriving from EventArgs

Tags:

c#

.net

The documentation for EventHandler<TEventArgs> says:

The second parameter is a type derived from EventArgs and supplies any fields or properties needed to hold the event data.

and it seems to be generally recommended throughout the .Net documentation.

However it turns out that I can do the following which works just fine:

public event EventHandler<int> Panned;

and invoke the event handler as:

int value = 10;
if (Panned != null)
{
    Panned(this, value);
}

and on the observer side:

subject.Panned += (sender, e) =>
{
    Console.WriteLine(e);
};

To me this seems better than littering the code with little classes that inherit from EventArgs or having a generic EventArgs as proposed by Does .NET have a built-in EventArgs<T>?

So why is it required that I inherit the EventHandler generic argument from EventArgs?

like image 258
Kostub Deshmukh Avatar asked Aug 04 '15 18:08

Kostub Deshmukh


2 Answers

If all you need to do is pass an int to the handler then what you are doing is fine.

It used to be the case (before .NET 4.5) that the EventHandler type argument TEventArgs was constrained to inherit from EventArgs but not anymore:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e); 

The fact that MS dropped the constraint should tell you that they were being too strict and what you are doing is fine.

In the case that you need to pass a complex type to the handler then you might aswell inherit EventArgs for reasons of polymorphism. Also, the EventArgs.Empty member is useful.

like image 190
Alex Booker Avatar answered Oct 18 '22 14:10

Alex Booker


This is just a convention. In fact, you don't even have to use the EventHandler<> generic delegate. You could have:

public event Action SomeEvent;

public void OnAction()
{
    var a = this.SomeEvent;
    if (a != null)
    {
        a();
    }
}

Of course, the convention is there for a reason. As far as I know, every standard .NET event follows the pattern of using a void-returning delegate that takes an object parameter and a second parameter of EventArgs or a derived type. This makes it easy to use these events without having to refer to the documentation each time.

Silly, Silly, Silly!

Will this work?...

class Program
{
    public static event Func<int> SomeEvent;

    static void Main(string[] args)
    {
        SomeEvent += () => 7;
        SomeEvent += () => 8;
        var a = SomeEvent();
        Console.WriteLine(a);
    }
}

I tried it: it does! Of course, it's very odd to have an event where the delegate has a return value, because it's not obvious which handler's value will be returned to the caller if there are multiple attached handlers. In the above example, it turns out that 8 is written to the console.

Interesting but, I suspect, useless ;-)

Would You Ever Use This?

I don't think it would ever be sensible to have a non-void returning delegate type, as in my example. However, you might consider using a delegate whose parameters are value types (structs, not classes) for performance reasons. It might be possible to use events without incurring the garbage collection penalty of allocating EventArgs objects on the heap.

like image 35
Olly Avatar answered Oct 18 '22 13:10

Olly