views:

138

answers:

5

I have a C# function that flips the orientation of a DataSet:

static DataSet FlipDataSet(DataSet my_DataSet)
    {
        using (DataSet ds = new DataSet())
        {
            foreach (DataTable dt in my_DataSet.Tables)
            {
                DataTable table = new DataTable();
                for (int i = 0; i <= dt.Rows.Count; i++)
                {
                    table.Columns.Add(Convert.ToString(i));
                }
                DataRow r = null;
                for (int k = 0; k < dt.Columns.Count; k++)
                {
                    r = table.NewRow();
                    r[0] = dt.Columns[k].ToString();
                    for (int j = 1; j <= dt.Rows.Count; j++)
                        r[j] = dt.Rows[j - 1][k];
                    table.Rows.Add(r);
                }
                ds.Tables.Add(table);
                table.Dispose();
            }
            return ds;
        }
    }

I modified this code from a snippet I found on the interwebs to wrap the created DataSet in a using statement and explicitly dispose of the IDisposable objects it creates. My question is, what happens to the DataSet ("ds" in the above code) when it is returned, in terms of disposal? I cannot explicitly call .Dispose() on ds after I return it, obviously, so does .NET return the value and then dispose of it properly, or am I missing something entirely?

+3  A: 

The ds DataSet will be disposed as soon as you leave the using block, so you'll be returning a disposed DataSet to the caller.

Why do you say that you can't call Dispose on the DataSet after you've returned it? I suspect that's exactly what you'll need to do.

Remove the using block from your FlipDataSet method and then dispose of the returned DataSet in the calling code, preferably by wrapping it in a using block.

LukeH
+8  A: 

You probably don't want to do this. The DataSet is disposed when the using block exits regardless of how the block exits (normal exit, return, or thrown exception), meaning that the value you return will have been disposed and be mostly unusable to the caller.

The right thing to do is to not have a using block in this function. The using block should be in the caller.

JSBangs
Thank you very much for your help. I hadn't considered the fact that the caller could be used to dispose of the DataSet.
Geo Ego
A: 

As LukeH says, there is probably a bug in your current code. If you remove that using statement for the DataSet and return it, then it's up to the caller of your method to Dispose of it properly which is how it has to be since your code can't tell when it should be disposed off.

ho1
+1  A: 

As mentioned in another answer already, you will return a disposed dataset. This is "A Bad Thing"TM.

I believe very strongly that every IDisposable should always be wrapped in a using block. However, sometimes the trick is exactly where that using block goes. For functions that return an IDisposable, you just create the object as normal. The using block wraps the line the calls the function.

Joel Coehoorn
+2  A: 

You already have some really good answer, but I want to present another persepective.

This is really a question of ownership. Whoever owns that DataSet is responsible for disposing it. But, who really owns it? In this case FlipDataSet creates the new instance but is transfering ownership because it returns that instance to the caller and does not continue to hold the reference itself. That means the lifetime management of the instance is now the caller's responsiblity.

It is beneficial to think in terms of ownership when generalizing this situation to other scenarios. Just because a property or method happens to return a IDisposable instance does not mean that it is transferring ownership. Ideally you would defer to that API's documentation for hints. However, in most of the cases I have seen there is an implication that if the instance is extracted from a property then that instance is still owned by the containing class and in that case it is not the callers responsiblity to manage lifetime. Likewise, if the instance is extracted from a method then it is usually the case that the method created that instance and makes no effort to continue holding a class reference to it and in that case it is the callers responsiblity to manage lifetime.

Brian Gideon
Thanks for the perspective. I see what you're saying about thinking about ownership, and while I have done that to a degree, I hadn't considered until today "who" is responsible for the disposal of objects created in this fashion. Thank you for broadening my thinking.
Geo Ego