views:

93

answers:

2

I wanted to know if there are any conventions regarding disposal of disposable items nested inside another disposable item(in a property/public field, not as private members). For example, a DataSet contains DataTable(s) and a SqlCommand contains a SqlConnection.

The obvious thing would be for a class to dispose of all Disposable items it owns, and leave the rest. Does there exist such a convention? If it does, how does .NET libraries determine who owns what? How can I find out whether nested objects are being disposed?

PS: I have been wondering about this for a while, and apparently so have others : What gets disposed when SqlCommand.Dispose is called?

Edit 1 : Found out that disposing DataSet, does not dispose its tables.

// Fill dataset from sqldataadpater.
foreach (DataTable dt in dataSet.Tables)
{
    dt.Disposed += Program.DisposedEventHandler2;
}
Console.WriteLine("Disposing dataset");
dataSet.Dispose(); //Event not fired here.
Console.WriteLine("Disposing datatables maually");
foreach (DataTable dt in dataSet.Tables)
{
    dt.Dispose(); //Event fired here
}
#endregion
+2  A: 

I would say that usually a container will dispose any contained disposable items - StreamReader disposes of the underlying stream, for example - but typically I will dispose of each item with a separate using statement anyway.

Any concept of "ownership" is really just in documentation and convention. Basically you have to know what will dispose of what, which typically means reading the documentation and hoping it makes it clear. Unfortunately it doesn't always do so :(

Note that there's no single correct answer here - sometimes you may want a type to behave one way, and sometimes the other. Some types explicitly allow you to state whether you're effectively transferring ownership of the resource, although most don't.

Jon Skeet
But while using a dataset for example, which I read from using a query, am I expected to dispose of the datatables(and the datatables contain datacolumns and so on...) it contains manually? I really can't think of an elegant way to do that.
apoorv020
I'm mostly worrying abut the BCL library, since their dispose methods don't have documentation and I use them a lot.
apoorv020
@apoorv020: `DataTable` and `DataSet` are oddities, to some extent. Unless you're using remoting, you don't need to dispose of them as far as I'm aware. They're really only disposable because they're remotable. They inherit disposability from `MarshalByValueComponent`.
Jon Skeet
@Jon: I added a suggestion to the Microsoft connect site about the `StreamReader` class. Let's all vote: https://connect.microsoft.com/VisualStudio/feedback/details/577258/add-constructor-overload-to-streamreader-to-prevent-it-to-dispose-the-underlying-stream
Steven
+5  A: 

The rule of thumb I normally follow is that the class that creates a disposable object, will also dispose it. As an example: An SqlCommond does not dispose its connection, because it didn't create it. The StreamReader has a strange behavior in this sense, because it will always dispose the underlying stream, even if it is supplied from the outside (I find this very annoying, please vote HERE when you like Microsoft to fix this).

Steven
While it's annoying sometimes, it means that you can use `new StreamReader(new FileStream(...))` and not have to worry about having two `using` statements... which can often improve readability, IMO.
Jon Skeet
@Jon: I understand why the BCL team choose this API design. It guides .NET developers to 'the pit of success' (as Rico Mariani calls it). However, I'm missing the overload with the enum or boolean flag that orders the `StreamReader` to keep the stream alive. In the current design, keeping the stream alive would mean you will have to wrap the stream with a `class DoNotDisposeStreamDecorator : Stream`.
Steven
@Steven: Yes, I've got exactly such a decorator myself...
Jon Skeet
System.IO.BinaryReader is the most annoying, someone hand you a stream as input parameter to one of your function, you choose this nice reader class to parse the binary data and bang you end disposing the stream...
VirtualBlackFox