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?
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:
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.
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:
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With