In VB.NET, if a type which implements IDisposable
has any variables that are declared WithEvents
, it is generally a good idea--and is sometimes very important--to set those variables to null
in the Dispose
method, since failure to do so will mean that objects to which those variables referred will be left holding back-references to the object that was disposed. That can cause serious memory leaks in the scenario where many short-lived objects subscribe to events from a long-lived object.
Although C# does not allow VB.NET-style WithEvents
declarations, it's possible to code properties in C# which behave similarly:
// Handle a property Wobbler which identifies an object whose Wibbled event
// I want to handle with my WibbleWobble method.
Woozle _wobble;
Woozle Wobbler {
get { return _wobbler; }
set {
var wasWobbler = _wobbler
if (wasWobbler == value) return; // Don't unsubcribe and resubscribe same object
if (wasWobbler != null)
wasWobbler.Wibbled -= WibbleWobble; // Unsubscribe old event
if (value != null)
value.Wibbled += WibbleWobble; // Subscribe new event
_wobbler = value;
}
};
If one uses a pattern such as that (it can be a nice way to ensure subscribes get paired up with unsubscribes), one should set Wobbler
to null
in one's Dispose
method, to ensure that any event that was attached to it gets detached.
Other than the aforementioned scenarios, it generally doesn't matter whether Dispose
sets things to null
, since the only thing one should be doing with the objects referred to by those fields is disposing them and cancelling their events, calling Dispose
multiple times on a well-coded object should be harmless. There are a few cases, however, were setting a field to null
in dispose may be helpful. Some collections store data using an array along with an indication of which slots hold meaningful data; if a collection "removes" an item from the array by indicating a slot doesn't hold anything meaningful, but doesn't null out the reference, that item and anything to which it holds a direct or indirect reference will be kept alive by the GC. If disposed objects null out their references to other objects, the amount of data kept alive by the collection may be minimized.
Incidentally, note that the code above is not thread safe, and cannot very cleanly be made thread-safe without locking, even if the subscribe/unsubscribe methods are thread safe and one uses only accesses _wobbler
via Interlocked
methods. If _wobbler
is updated before subscriptions/unsubscriptions are processed, then if Wobbler
is to some object George in one thread and to something else in another, the second thread might send George an unsubscribe request before the first thread has sent its subscription request (resulting in a dangling subscription). If it's not updated before processing subscriptions/unsubscriptions, then two simultaneous attempts to set Wobbler to George could result in George being given two consecutive subscription requests (which could eventually result in a dangling subscription).