Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why copy an event handler into another variable

Tags:

c#

In an example, I find this code:

public event EventHandler ThresholdReached;

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

I would like to understand the reason for the line:

EventHandler handler = ThresholdReached;

Can we not just do it this way:

public event EventHandler ThresholdReached;

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

Are there some advantages/disadvantages to either way of doing it?

like image 681
Graham Avatar asked Dec 12 '19 09:12

Graham


People also ask

How to copy event handlers from one control to another?

Now, press the button named “Copy event handlers” and enter some text in the textbox labeled Destination. If all goes well, you should see the messages from the event handlers attached to the Source textbox now attached to the Destination textbox. For copying handlers from one control to another, you just need those two lines of code:

How to pass a variable into an event listener/handler function?

It can be tricky getting variables into event listener/handler functions. It’s even harder to get variables back out of event handlers again. Suppose you want to pass a variable into an event handler. First you might store a reference to a DOM element in a variable. Let’s use myElement for that.

Is the event handler a method on the class?

When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class. For example, this Toggle component renders a button that lets the user toggle between “ON” and “OFF” states:

How to pass an object as an argument to an event handler?

Here’s the problem: in this case you need your event handler to be defined within an object, and you need to pass a property belonging to the object into the event handler function. However, since all event handlers are called by the event listener interface, and not called directly, there is no way to specify an argument to pass to yours.


2 Answers

The problem is that between this line

if (ThresholdReached != null)

and this line

ThresholdReached(this, e);

a different thread could have removed the handlers from the ThresholdReached event. So it would be null and an exception would be thrown.

By storing the value in a local variable, you make the call thread-safe.

Since C# 6 you can shorten the code to this

ThresholdReached?.Invoke(this, e);

Now the compiler takes care of storing the value in a temporary variable.

like image 171
René Vogt Avatar answered Nov 06 '22 23:11

René Vogt


There's a theoretical risk of a thread race in the second version where someone unsubscribes the event between the check and the invoke, causing a NullReferenceException in the invoke step. Capturing the value into a local and testing/invoking that prevents this. However, perhaps use the third version, possible with C# 6 or above (thanks @Cid):

ThresholdReached?.Invoke(this, e);

This is basically a short-hand version of the first version - all the safety, but now with terseness.

like image 25
Marc Gravell Avatar answered Nov 07 '22 00:11

Marc Gravell