Reputation: 11054
When adding handlers indiscriminately to an object's events, I realized that I can attach the same handler to an event as many times as I like. This means the handler is called once for each time it was attached.
I'm wondering these things:
Upvotes: 3
Views: 452
Reputation: 156469
The correlations between an event and its handlers are stored on the event itself. When you access the event, this information is actually copied out into a method group. That's why you're supposed to say:
var onclick = Click;
if (onclick != null) onclick();
If I accessed the Click
event twice rather than using the intermediate onclick
variable, I would have caused any events to be copied twice. Also, in a multi-threaded scenario, if someone removed a handler between checking Click != null
and invoking the handler, I could end up throwing an exception.
If you already know which handler you want to remove, it is easy to remove that handler:
EventHandler handler1 = (sender, e) => Console.WriteLine("test");
Click += handler1;
Click -= handler1;
There is a way to get some basic information about each handler that was added to an object's event, via GetInvocationList
:
foreach(var handler in Click.GetInvocationList())
Console.WriteLine(handler.Method.ToString());
However, the information you get out is in the form of a Delegate object. It can be invoked (which can be useful if you want to catch any exceptions thrown by one handler, and continue invoking the remaining handlers), but C# doesn't provide an easy way to remove the handler from the event based solely on this information. Some of the answers at How to remove all event handlers from a control seem to indicate that you can use Reflection to do it, or you can use Visual Basic's RemoveHandler
command.
Upvotes: 1
Reputation: 44307
If the event is marked with the C# event keyword then there's no way from outside the object to see the subscribers - the requisite information is just not visible.
From inside, it can be done, though it is complex and relies on details of implementation that might change (though, they haven't yet).
A workaround that might be useful for you though, is that it's valid to remove a handler that's not there - no exception is thrown.
So this code is valid:
myConnection.Closing -= ConnectionClosingHandler;
myConnection.Closing += ConnectionClosingHandler;
If you're already subscribed to the event, the first line removes the subscription.
If you're not already subscribed to the event, the first line does nothing.
The second line then hooks up a new subscription, and you're guaranteed not to be notified multiple times.
To answer your last bullet point, when you declare a normal event:
public event PropertyChangedEventHandler Changed;
The compiler creates a member variable of type PropertyChangedEventHandler
which stores all the subscribers. You can take over storage if you want:
public event PropertyChangedEventHandler Changed
{
add { ... }
remove { ... }
}
The use of -=
and +=
to modify the subscription isn't syntactic sugar - the delegates are immutable, and a new instance is returned when you add or remove a handler. Have a look at Delegate
and MulticastDelegate
(both MSDN links) for more information on how this works.
Upvotes: 2