As per my understanding when an Object is no longer required it is best practice to unsubscribe all event handlers in any Objects that subscribes to events.
This is done to avoid handling an event within an Object when the given Object may reside in a invalid state (no doubt among other reasons that I'm probably unaware of).
Given the above, I have found myself implementing IDisposible
on all my Objects that register any form of event handlers. However, this creates the obvious complexity of having to explicitly call Dispose()
on the given object.
In the end, I find myself uncertain if this extra complexity is required or if I should simply perform the event unsubscription in the object destructor. However this obviously leaves open the possibility of unexpected behavior given that Object destruction is non-deterministic.
So should all Objects that register for events be IDisposable
? Or is there an alternative approach that is better suited?
I would suggest that if an object subscribes to notifications from outside objects, whether those objects use events,
IObservable
, or other means of subscription, disposing the object should ensure that those subscriptions get canceled; the most natural way to do that is for it to use the normal means of cancellation supported by those outside objects.I would further suggest that if an object accepts subscription requests from outside objects, it should destroy references to those objects if/when it becomes apparent that no notifications will ever again be sent to those subscribers. Generally, once an object has sent any notifications that would be required by
Dispose
itself, it won't have to send any further notifications and should thus destroy its subscription lists unless its semantics require them to be kept beyond that.While the .NET event pattern does not make it convenient to ensure that subscriptions get cancelled, failure to cancel subscriptions from shared objects will often result in code which will "usually" work, but will have some hard-to-validate requirements. In cases where a few objects are created and kept, or an unbounded number are created and all are abandoned, mutual references among the objects won't cause memory leaks since in the former case the objects would need to be retained even if the mutual references didn't exist, and in the latter case they would cease to exist despite the mutual references. Cases where an unbounded number of objects are created and all but a few are abandoned, however, can be disastrous. Even if many objects' consumers will naturally abide by one or the other usage pattern, requiring that all must abide by one, or all by the other, without specifying which pattern is acceptable, is rather awkward.