Other questions and answers advocate using the IDisposable
interface to unsubscribe from events that an object subscribes to in its constructor. What I'm failing to understand is why the Dispose()
method gets called in the first place.
Consider the code (verbatim) from this example:
public class DetailViewModel : IDisposable
{
public DetailViewModel(MyDetailModel detailModel)
{
// Retain the Detail Model
this.model = detailModel;
// Handle changes to the Model not coming from this ViewModel
this.model.PropertyChanged += model_PropertyChanged; // Potential leak?
}
public void Dispose()
{
this.model.PropertyChanged -= model_PropertyChanged;
}
}
So supposing that this model is referenced by the DataContext
of some window, then it should have no references when that window is closed and garbage collected. But the event detailModel.PropertyChanged
will still hold a reference to the delegate (which is why we're unsubscribing in the first place). And each delegate is implemented as a compiler-generated class which will hold a reference to the instance (the DetailViewModel
) in its auto-generated _target
field.
So does _target
not count as a reference to the DetailViewModel
?
I see two cases.
- It does count, and the
DetailViewModel
lives as long as the event it's subscribing to does, andDispose
won't benefit anything since it won't be called until after the subscribed object gets garbage collected. - It doesn't count, and then the
DetailViewModel
gets disposed of which would call the event removal code. Ok, no more space leak. But if you don't implementIDisposable
, and the event gets fired and tries to call your delegate, which now points to a deleted object, why doesn't the program crash? Does the CLR just swallow the exception?
I've only been coding C# for about a month, so if I'm really fundamentally misunderstanding something, please let me know.