10

I've been trying to learn how to use event handlers in C# but I can't figure out what handler(this, e) does in the following code:

public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(EventArgs e)
{
    EventHandler handler = ThresholdReached;
    if (handler != null)
    {
        handler(this, e);
    }
}

Is it trying to call the event handler method (this) with the event (e)?

Tony
  • 1,839
  • 10
  • 27
  • 48

7 Answers7

14

It invokes all registered event listeners which are registered on the ThresholdReached event.

The handler != null check makes sure at least one listener is registered to that event.

In C# 6.0 and above you can use Null Propagation:

handler?.Invoke(this, e);

handler(this, e) will call every registered event listener. Event listeners subscribe with help of the += operator and unsubscribe with -= operator to that event.

this is there to give the event listener to know who raised the ThresholdReached event. Who was the sender of the event.

e is the event argument which is also passed into the listener method which can contain more useful informations about the ThresholdReached event e.g. which threshold was reached.

BlueM
  • 6,523
  • 1
  • 25
  • 30
  • Thanks for the explanation. How might you register a listener to the event though? – Tony Aug 31 '12 at 15:18
  • With the += operator. Like in your other class yourInstanceWithTheEvent.ThresholdReached += SomeThresholdReachedHandler; – BlueM Aug 31 '12 at 15:20
1

It is raising a ThresholdReached event with arguments sender=this and eventarguments = e. In fact, it is the same as the following;

public event EventHandler ThresholdReached;

protected virtual void OnThresholdReached(EventArgs e)
{
    if (ThresholdReached != null)
    {
        ThresholdReached(this, e);
    }
}

If there are any listeners to this event; it will simply call listener delegates;

this.ThresholdReached += new EventHandler(Form1_ThresholdReached);

Then, when this event is raised Form1_ThresholdReached function will be called with this and e parameters.

daryal
  • 14,643
  • 4
  • 38
  • 54
  • 2
    @daryal: Imagine what happens if the last listener unsubscribes after the != null check. – BlueM Aug 31 '12 at 14:51
  • @Oded does not the "handler" and the "ThresholdReached" point to the same reference? Sorry if i am missing some point. – daryal Aug 31 '12 at 14:57
  • @daryal - No. The invocation list is _copied_ to the `handler` reference. See [this blog post](http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx) by Eric Lippert on the subject. – Oded Aug 31 '12 at 15:07
  • Maybe it helps to understand that an event is an instance variable which holds a reference to a MultiCastDelegate http://msdn.microsoft.com/de-de/library/system.multicastdelegate.aspx If the last listener unsubscribes, it will remove that multicastdelegate instance and set the event to null. – BlueM Aug 31 '12 at 15:11
  • Sorry I was mistaken about events being multicast delegate instances. But read http://csharpindepth.com/Articles/Chapter2/Events.aspx "Thread safe events" for more information. – BlueM Aug 31 '12 at 15:18
1

The code in your example copies all registered handlers to the local variable handler, checks that the invocation list is not empty and invokes all members of the copied invocation list with the arguments this and e.

The reason for the fact that you get a snapshot of the current invocation list is that delegates are immutable. You get a reference to the current multicast delegate, and when handlers are added or removed the backing field points to a new delegate created from two immutable ones.

The usual reason to copy the invocation list to a local variable is some form of thread-safety: a handler could be unsubscribed between the usual nullity check (check that the invocation list isn't empty) and the actual invocation: that way you might accidentally fire an event with no handlers and a NullReferenceException would be thrown.

Steve Czetty
  • 6,147
  • 9
  • 39
  • 48
DoomMuffins
  • 1,174
  • 1
  • 9
  • 19
0

Is it trying to call the event handler method (this) with the event (e)?

No, not literally. It is calling the event handler with the EventArgs e and using this as sender. It might as well be:

if (ThresholdReached != null)
{
    ThresholdReached(this, e);
}

Or, to circumvent the null check:

public event EventHandler ThresholdReached = delegate { };

protected virtual void OnThresholdReached(EventArgs e)
{
    ThresholdReached(this, e);
}

But, as @Oded noted, the first piece isn't thread-safe, because EventHandler handler = ThresholdReached creates a copy of the handler, which is better explained in this question.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

handler refers to your ThresholdReached event. So, if anyone is subscribing to ThresholdReached events, their registered handler will be called with arguments thisand e.

ekholm
  • 2,543
  • 18
  • 18
0

It is Triggering the ThresholdReached event. Passing a reference to itself, this. Passing arguments about the event in e.

burnttoast11
  • 1,164
  • 16
  • 33
0

The call to handler represents a function call in another object or class. When you create the object, you will be able to write a piece of code that looks like this:

obj.ThreasholdReached += new EventHandler(someFunction);

someFunction in that class will be defined like this

public someFunction(object sender, EventArgs e) {...}

the OnThreasholdReached function in the original object is what publishes the event to any other class that has assigned a function to the ThreasholdReached handler. Using handler as a go-between is an entirely unnecessary extra step. You are still saying if ThreasholdReached != null, its the same thing.

In Summary: The line of code handler(this, e) is actually the call to whatever subscriber someFunction(object sender, EventArgs e) has been assigned to the ThreasholdReached event of the object.

Nevyn
  • 2,623
  • 4
  • 18
  • 32