Re: Event Subscription. Why?
- From: Morten Wennevik [C# MVP] <MortenWennevik@xxxxxxxxxxx>
- Date: Thu, 7 May 2009 23:09:01 -0700
"Peter Duniho" wrote:
On Thu, 07 May 2009 02:31:01 -0700, Morten Wennevik [C# MVP]
<MortenWennevik@xxxxxxxxxxx> wrote:
I didn't intend to show the exact translation although I probably should
have made that clearer.
Actually the code translates to
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_MyEvent(EventHandler<MyEventArgs> value)
{
this.MyEvent = (EventHandler<MyEventArgs>)
Delegate.Combine(this.MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MyEvent(EventHandler<MyEventArgs> value)
{
this.MyEvent = (EventHandler<MyEventArgs>)
Delegate.Remove(this.MyEvent,
value);
}
Now, that...the above...is exactly the same as the code I posted.
No it isn't. The whole point was to show that +=/-= translates to method
calls, your code still used +=.
I.e. if
you compile the two, you get exactly the same IL (with the exception that
the above won't actually expose an event on the class without more code),
and both examples show precisely _what_ the implementation is.
The point is, there's an implicit implementation, and that implicit
implementation looks nothing like what you posted the first time around.
No, but still, the point was to indicate that += translates to method calls
which may return null.
Combine internally works with an object[] which is a list although not a
List. Each time you add or remove a subscriber you will create a new
list so
each call to MyEvent will only work with the current list. In that
regards
just using add/remove of a List<EventHandler> may give an incorrect
understanding of events.
I think that's a bit of an understatement. :)
As for creating a reference before checking for null, that is relevant
only
if you unsubscribe from another thread,
So is the synchronization in the event's add and remove methods. So?
Both are still considered "more correct".
and may actually cause the event to
notify a subscriber that is no longer subscribing, or even worse, no
longer
exists.
The latter is not possible. The former is, but that's not a flaw. It's a
completely unavoidable situation and just means you need to understand how
events work. Subscribers cannot make the assumption that they have
successfully unsubscribed from the event, without some kind of explicit
coordination with the publisher of the event (which usually isn't present).
Sure you can delete a subscriber. It may not have been garbage collected,
and actually it never will unless you unsubscribe (causing a nice memory
leak), but calling a method on such a subscriber may have nasty side effects.
Then again, as you said, the subscriber should test for such state when
handling the event. It would be nice if we could always rely on the
subscriber to do this.
What the best solution is depends on the implementation. If you
tend to delete the subscriber after unsubscibing it may be safer not
creating
the reference.
Again, you cannot "delete the subscriber". The subscriber is a .NET
managed object, and as long as the publishing class has a reference to it,
it continues to exist.
As I said above. Also, with remoting the subscriber may well be garbage
collected as well and therefore is completely gone when you try to call it.
Then again, remoting does not support normal event handling so the point is
kind of moot.
It is not possible to ensure that a subscriber is not called after the
subscriber has executed code to unsubscribe without additional work (for
example, you could synchronize on the same object in both the add and
remove methods, as well as when raising the event...but that's a pretty
extreme solution, and holding a lock while calling external code -- such
as an event subscriber's handler -- is generally a very bad idea).
In fact, you may find this recent and timely post from Eric Lippert
useful. It discusses this exact topic:
http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx
Pete
As well as the thread that may have triggered Eric to write that post ;)
http://stackoverflow.com/questions/786383?sort=oldest
To sum up:
Subscribing or unsubscribing to an event will cause a new list of
subscribers to be created. If there are no subscribers the list will most
likely be null.
Two subsequent calls to a subscriber list may return two different results.
if(MyEvent != null) // may not be null here
MyEvent(); // ... but may be null here
Again, this is only relevant where someone unsubscribes from MyEvent from
another thread, but unless you can be sure noone never will it would be wise
to either use a single list or ensure MyEvent is never null.
If you hold a reference to the list of subscribers it may be outdated when
you use it. Some of the subscribers may have unsubscribed.
The subscriber is not guaranteed to be unsubscribed after he unsubscribes,
but subscribers usually believe so. Someone may hold a reference to a list
prior to the unsubscription.
Happy Coding!
Morten Wennevik [C# MVP]
.
- Follow-Ups:
- Re: Event Subscription. Why?
- From: Peter Duniho
- Re: Event Subscription. Why?
- References:
- Event Subscription. Why?
- From: bob
- RE: Event Subscription. Why?
- From: Morten Wennevik [C# MVP]
- Re: Event Subscription. Why?
- From: Peter Duniho
- Re: Event Subscription. Why?
- From: Morten Wennevik [C# MVP]
- Re: Event Subscription. Why?
- From: Peter Duniho
- Event Subscription. Why?
- Prev by Date: Re: how to change the default properties of textbox
- Next by Date: Re: how to change the default properties of textbox
- Previous by thread: Re: Event Subscription. Why?
- Next by thread: Re: Event Subscription. Why?
- Index(es):
Relevant Pages
|