Q & A On IDisposable and Memory Management
Wasn't this supposed to be easier?
Hi Bill
I am an independent MSCD for Microsoft .NET, and I always enjoy your
writing.
Your article beautifully explains the Dispose application implementation
pattern. However, there is one important aspect which you do not address and
which, in the whole MSDN library, is only documented with one single sentence:
"Developers must propagate Dispose throughout a containment hierarchy to ensure
that children of a component also free resources".
It took me a lot of research to 1) find this best practice rule and 2) figure
out what Microsoft most probably means by it. The words "containment hierarchy",
"children" and "component" can mean many different things, depending on whether
you look at it strictly from the .NET Framework or from a more general OOP point
of view.
In my interpretation, the rule applies strictly to any class who
implements System.ComponentModel.IComponent (such as System.Data.DataSet) and
has children who also implement System.ComponentModel.IComponent (such as
System.Data.DataTable) who
depend on the parent through an intermediate class who implements
System.Collections.IEnumerable (such as System.Data.DataTableCollection).
Knowing this rule has important consequences. As to the consumers of
disposable classes, it saves them a lot of coding because they only have to
dispose the DataSet explicitly, but not all the DataTables. The same is true for
Forms and their Controls. On the other hand, if a disposable class is not an
IComponent, or if a disposable class has dependent objects who are not in an
aggregation relationship to the class, they must call Dispose on each and every
dependent object explicitly. As to the developers of disposable classes, they
must apply additional best practices if their class is an IComponent who in some
way contains other enumerable IComponents.
If you check the Internet discussion threads, you will see that many
programmers struggle with the best practices regarding IDisposable. I hope that
Microsoft will document this more clearly, or maybe you will address this aspect
in one of your future articles.
Best regards
Marc
======================== My Response ==========================
Marc,
First, let me address a couple knits: IComponentModel is derived from
IDisposable. For that reason, your recommendations about IComponentModel are in
line with what I said, only for IDisposable.
Let me address your second point, about disposing only what you need, and
exactly what you need. Much of the confusion comes from many developers'
internalizing C++ destructor rules. IDisposable is different: it is legal to
dispose of an object more than once. As a class author, that means you must
handle the case where an object gets is disposed method called multiple times.
For your specific example, it is legal to dispose of every DataTable in a
DataSet. It's inefficient and unnecessary, but it is legal and will do no
harm.
As a class user, it's a little fuzzier. You should Dispose of those objects
you "own", ownership being a fuzzy term in .NET. In your example, the DataSet
"owns" the DataTables, so the DataSet disposes of them. Your form "owns" the
DataSet, and disposes of it. The Form does not own the DataTable, so no extra
dispose is needed.
But like I said, ownership in .NET is a bit fuzzy. Consider this snippet:
public void AddSettingsTable( Dataset s )
{
DataTable t = new DataTable( "Settings" );
AddColumns( t );
s.Tables.Add( t );
}
The Dataset, s, owns the table now, even though you created it in your form.
In short, you're right, if "containment" means "members whose lifetime
matches the containing object". Further, you should substitute IDisposable for
IComponent, as that is more correct.
Thank you for the letter, I'm glad you liked the article.
C# Pro article on Memory ManagementThe source article on the subject