Usually answers to questions like this can be found either here or, if not here, on MSDN, but I have looked and looked and not found the answer. Experimentation seems to show that code like:
SomeControl.Click += null;
does no harm. Or at least that firing the event doesn't toss an exception (that I can tell) by trying to invoke a null event listener. However, there seems to be nowhere on the Web that will validate my hope that such code isn't doing at least something that I might not want done. For example, causing the Click event to think it has listeners when it might not, and wasting those ever-precious super-ultra-mini-microseconds in "now let's perform null-checks and invoke all listeners that are not null" code.
It seems that documentation should say what the behavior of the += and -= operators is if the listener on the RHS is null. But like I say, I can't find that documentation anywhere. I'm sure someone here can provide it, though....
(Obviously, my code doesn't have a hard-coded null; my question is more about whether code like this is wasteful or completely harmless:
public static void AddHandlers([NotNull] this Button button,
[CanBeNull] EventHandler click = null,
[CanBeNull] EventHandler load = null)
{
button.Click += click;
button.Load += load;
}
or if I should [i.e., need to for any reason] add null-checks around each such += operation.)
JavaScript | removeEventListener() method with examplesThe removeEventListener() is an inbuilt function in JavaScript which removes an event handler from an element for a attached event. for example, if a button is disabled after one click you can use removeEventListener() to remove a click event listener.
With this approach, the event always has at least one subscriber, and is, therefore, never null.
To remove all event listeners from an element: Use the cloneNode() method to clone the element. Replace the original element with the clone. The cloneNode() method copies the node's attributes and their values, but doesn't copy the event listeners.
Consider this code:
void Main()
{
var foo = new Foo();
foo.Blah += Qaz;
foo.Blah += null;
foo.OnBlah();
}
public void Qaz()
{
Console.WriteLine("Qaz");
}
public class Foo
{
public event Action Blah;
public void OnBlah()
{
var b = Blah;
if (b != null)
{
Console.WriteLine("Calling Blah");
b();
Console.WriteLine("Called Blah");
}
}
}
As is it runs without error and produces the following output:
Calling Blah
Qaz
Called Blah
If I remove the line foo.Blah += Qaz;
then the code runs without error, but produces no output, so the null
handler is effectively ignored.
As far as IL goes, the line foo.Blah += null;
produces the following IL:
IL_001A: ldloc.0 // foo
IL_001B: ldnull
IL_001C: callvirt Foo.add_Blah
IL_0021: nop
So, it behaves as a nop
, but it clearly runs the code.
The answer depends on whether the +=
(or -=
) operator is being applied to an event or a delegate.
In your AddHandlers
example, the Button
class probably defines Click
and Load
as events, not delegates. When its left operand is an event, the +=
operator simply invokes the add
accessor of the event without any additional null checks. That is, under the covers button.Click += value;
is just a method call:
button.add_Click(value);
Like any other method, how add_Click
deals with a null argument is entirely up to the Button
class.
Now consider how the Button
class might actually implement the Click
event. Here's one way:
private EventHandler _click;
public event EventHandler Click
{
add { _click += value; }
remove { _click -= value; }
}
// Or even shorter...
// public event EventHandler Click;
// ... which is the same as above plus extra stuff for thread safety.
In this implementation, EventHandler
is a delegate type. When both operands are delegates, the +=
operator invokes Delegate.Combine
. The documentation says that Delegate.Combine(a, b)
returns:
A new delegate with an invocation list that concatenates the invocation lists of a and b in that order. Returns a if b is null, returns b if a is a null reference, and returns a null reference if both a and b are null references.
Conclusion: As long as the Button
class implements its events in the "standard" way (rather than, say, keeping track of listeners in an explicit List<EventHandler>
), then button.Click += null;
will ultimately not add a null listener.
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