This question is a follow up to the C# Events and Thread Safety question (I am not the author of that one) and the related blog post by Eric Lippert Events and Races. There are other similar questions on SO, but none of them actually consider this case, general consensus is that so long as you unsubscribe you are safe, but I don’t believe that is true all the time.
According to the discussion in both the SO question and the blog, the pattern that should be used is something like:
var ev = NotifyPropertyChanged;
if (ev != null)
ev(this, new PropertyChangedEventArgs("Foo"));
But what if the following situation occurs:
1) I subscribe a listener:
mytype.NotifyPropertyChanged += Handler; // Handler is instance method in SomeObject class
2) I (or the run-time, due to scoping) dispose SomeObject, which contains the listener and unsubscribe the listener, at about the same time the property notification happens.
3) While unlikely due to very short time period this can happen in, it is theoretically possible that because ev preserves the old subscriber that is no longer in existence, it will call a function in an object that no longer exist.
According to the Eric Lippert, “event handlers are required to be robust in the face of being called even after the event has been unsubscribed“. But if the handler is unsubscribed and disposed, it can no longer take care of the call. What is the correct way to handle this situation?
Wrap the code from (1) in try-catch? What exception should be caught? ObjectDisposedException seems likely, but not the only one that can happen, I think.
I believe that you meant to say an object that has already been GC’d, not disposed. Well that can’t happen; the
MultiCastDelegate(theEventHandler) maintains a reference to the object via its subscribed method, i.e., it can’t be GC’d until the handler is removed.Dispose()has nothing to do with a method not being available, it is a pattern used to cleanup native resources, i.e., resources that cannot be handled by the GC.The object itself is still alive and well, though it may throw an exception if you call a method that depended upon that native resource (depends on implementation of course. The point is that the object still exists as does the method).
There is nothing magical happening when you call
Dispose(). I could easily whip up a class that implementsIDisposableand has a completely emptyDispose()method. Call it all you will, it does nothing and does not change the state of the object in any way.