I found out that if you subscribe to or unsubscribe from an event in
the method that gets event handler as a parameter, it does not work as
expected.
If the event is declared as
event MyEventHandler myEventHandler;
you can subscribe to the event, using the construction
myEventHandler += subscriber;
but you cannot do the same by sending event handler as a parameter to
a method of the same class.
Construction
void AddSubscription(MyEventHandler myEH, MyEventHandler subscriber)
{
myEH += subscriber;
}
does not work, being called as
AddSubscription(myEventHandler, subscription);
"Does not work" means that subscription was successfully added to the
copy of the event invocation list, not to the original event.
At the same time, if AddSubscription() method has a slightly different
signature and event handler is sent by reference, it works:
void AddSubscription(ref MyEventHandler myEH, MyEventHandler
subscriber)
{
myEH += subscriber;
}
does work, being called as
AddSubscription(ref myEventHandler, subscription);
Some additional investigation shows that if you have the same two
event handler objects they are treated as equal until one of them is
changed.
MyEventHandler myEventHandler2 = myEventHandler;
bool b = myEventHandler2.Equals(myEventHandler); //true
myEventHandler2 += subscriber;
//at that moment myEventHandler2 has one more subscribers then
myEventHandler;
bool b = myEventHandler2.Equals(myEventHandler); //false
Since Delegate is not a Value Type, it looks as the system creates a
new object copy at the moment some changes are done (I could not find
any documentation about that).
It seems like by using ref, we found the workaround the problem.
However, if an event is thrown using BeginInvoke() and EndInvoke() as
it is for remote clients to support died client deletion, our
workaround does not work. BeginInvoke() uses AsyncCallback delegate as
its parameter. The only way to send the event handler to the callback
method is to set it as an object field and send the object as
AsyncState (BeginInvoke() last parameter). However, doing that we are
loosing the reference spec. So, I don't know how to overcome it.
The scenario when you want to use one set of methods for working with
a set of events could be very useful if your class has a plenty of
events each one of them has the same associated methods differ only by
event handlers' and EventArgs' names.
Is such a behavior of event handler a bug?