4

A question came up during a code review the other day about how quickly a using block should be closed. One camp said, 'as soon as you are done with the object'; the other, 'sometime before it goes out of scope'.

In this specific example, there are a DataTable and a SqlCommand object to be disposed. We need to reference both in a single statement, and we need to iterate the DataTable.

Camp 1:

List<MyObject> listToReturn = new List<MyObject>();
DataTable dt = null;
try
{
    using (InHouseDataAdapter inHouseDataAdapter = new InHouseDataAdapter())
    using (SqlCommand cmd = new SqlCommand())
    {
        dt = inHouseDataAdapter.GetDataTable(cmd);
    }

    foreach (DataRow dr in dt.Rows)
    {
        listToReturn.Add(new MyObject(dr));
    }
}
finally
{
    if (dt != null)
    {
        dt.Dispose();
    }
}

Reasoning: Dispose the SqlCommand as soon as you are done using it. Don't start potentially long operations, such as iterating the table, within another object's using block.

Camp 2:

List<MyObject> listToReturn = new List<MyObject>();
using (InHouseDataAdapter inHouseDataAdapter = new InHouseDataAdapter())
using (SqlCommand cmd = new SqlCommand())
using (DataTable dt = inHouseDataAdapter.GetDataTable(cmd))
{
    foreach (DataRow dr in dt.Rows)
    {
        listToReturn.Add(new MyObject(dr));
    }
}

Reasoning: This code is much cleaner. All objects are guaranteed to be disposed no matter what, and none are really resource-intensive, so it is not important to dispose any immediately.

I'm in Camp 2. Where are you, and why?

Edit: Several people have pointed out that DataTable need not be disposed (see Corey Sunwold's answer) and that Camp 1's original example is uglier than it needs to be. Here are some revised examples that also take into account the fact that most of the time, I have to set some properties on the SqlCommand. If anyone has seen or can think of a better example to support either position, please share it.

Camp 1, version 2:

DataTable dt = null;
using (InHouseDataAdapter inHouseDataAdapter = new InHouseDataAdapter(_connectionString))
using (SqlCommand cmd = new SqlCommand("up_my_proc"))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add("@class_id", 27);
    dt = inHouseDataAdapter.GetDataTable(cmd);
}

foreach (DataRow dr in dt.Rows)
{
    listToReturn.Add(new MyObject(dr));
}

Camp 2, version 2:

using (InHouseDataAdapter inHouseDataAdapter = new InHouseDataAdapter(_connectionString))
using (SqlCommand cmd = new SqlCommand("up_my_proc"))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add("@class_id", 27);
    DataTable dt = inHouseDataAdapter.GetDataTable(cmd);
    foreach (DataRow dr in dt.Rows)
    {
        listToReturn.Add(new MyObject(dr));
    }
}

I think most people will agree that the readability argument is now much reduced, and that this is not the best example of what I am trying to ask. (That is especially true once I tell you that the SqlConnection is closed before the GetDataTable() method exits, and there is no measurable performance difference for the data used in this instance.) If I may add to my question this late, are there instances where it does make a difference whether I dispose the object immediately? For example, as Gregory Higley mentioned, a shared resource like an OS handle.

Edit: (Explaining my choice of answer) Many thanks to all who contributed opinions, examples, and other helpful feedback! We seem to be split about evenly, but what stands out from everyone's answers is the idea that 'camp 1 is definitely right, but depending on the object, camp 2 may be okay'. I meant this to be a general discussion of disposal of all types of objects, but I chose a bad example to illustrate it. Since much of the discussion focused on that particular example, I have chosen the answer that gave me important information about the specific objects in use, and proved that I need to consider each object carefully when making this kind of decision. (It would be difficult to choose a 'best answer' to a question as vague as what is in my title, anyway.) Future readers with the same dilemma, please see all the answers below, as many of them raise interesting points.

Community
  • 1
  • 1
Kimberly
  • 2,657
  • 2
  • 16
  • 24
  • The reviewer is being overzealous - it doesn't really matter unless the DataTable has heaps of rows. The main thing is that you *are* disposing your objects and the application performs well (and of course that the code is readable). – Greg Sansom Mar 31 '11 at 03:00
  • Camp 2 FTW! and this makes 15. – Marcote Mar 31 '11 at 03:10
  • Between these two examples, I would choose Camp 2 as well, but considering @Corey Sunwold's answer, you could get rid of the `try finally` in the Camp 1 answer and it would look pretty clean. Also, in both cases, I think you should check that `dt != null` before the `foreach`. – Jeff Ogata Mar 31 '11 at 03:54
  • @adrift Yes, I feel like the question is misleading now in light of Corey's point. As one answerer said, the entire example seems contrived (though it's actually not), and Camp 1's version is a "straw man" attack on the 'dispose early' argument. Should I edit the examples when there are so many answers already? Or add revised examples? – Kimberly Mar 31 '11 at 04:27
  • @adrift I thought of adding the null check for completeness, but it complicates each answer equally, so I left it out for brevity's sake. (In our case, dt will never be null because of the way the GetDataTable() method is implemented: it will throw an exception if it cannot return the data. I don't think this is the correct behavior, but I know it will not change because many applications are now dependent on it.) – Kimberly Mar 31 '11 at 05:06
  • "as soon as you are done with the object" +1 – Kieren Johnstone Mar 31 '11 at 15:13

9 Answers9

3

Mostly I agree with camp 1. However, you should note its probably not necessary to dispose a DataTable.

Community
  • 1
  • 1
Corey Sunwold
  • 10,194
  • 6
  • 51
  • 55
  • Interesting. I had never seen this before, so thanks for pointing it out. My example is real, not contrived, so our dilemma is solved by this. But I suppose there must be other types of objects for which immediate disposal uglifies the code. We'll see what shakes out in other answers. – Kimberly Mar 31 '11 at 03:02
  • @Kimberly I'm just happy to see people actually taking advantage of using blocks. You don't know how much C# code I've seen where the people writing it don't understand what IDisposable objects are or why Dispose matters. – Corey Sunwold Mar 31 '11 at 03:12
1

I think it depends upon what kind of unmanaged resources are held by the disposable object. Overall though, I'm with you in Camp 2.

If the unmanaged resource is shared in some way, particularly if it represents an operating system handle of some kind, I'd try to dispose of it as quickly as possible.

Gregory Higley
  • 15,923
  • 9
  • 67
  • 96
0

I am in Camp 2 as you do. Sometimes criticality of the resources are determined by available resources on the machine. Camp 2 solution does believe in preventive measure where remove the objects as you are done rather than the lazy Camp 1.

sajoshi
  • 2,733
  • 1
  • 18
  • 22
0

We usually go with camp 2 - for the reason that the outside using statement uses a SqlTransaction object.

We need the transaction to be disposed at the end so if an exception is thrown when using the data reader, the tranaction can be rolled back.

Russell
  • 17,481
  • 23
  • 81
  • 125
0

The Camp2 is more readable, so I would prefer it over Camp1 in most cases. The more readable your code is, the less pain you get in supporting it.

In some rare cases I would prefer Camp1 if there would be clear need to dispose resource very very quickly. I mean that if you encountered some problems disposing connection a bit later. But in most cases there wouldn't be any penalty if you go the Camp2 way.

Dmitrii Lobanov
  • 4,897
  • 1
  • 33
  • 50
0

It all comes down to how long do you think it is reasonable to hold onto an external resource. Data connections arent for free, so it makes sense to clean them up as soon as possible. For readability I would still maintain my stance as it is very clear as to what is the resource retaining objects here.

But in reality this is a bit of a purest question since we are talking low milliseconds here. I would say err on the side of camp 1, especially if you have a long running use of the data queried.

Also I would get rid of the DataTable clean-up. Its not needed on a managed object with no resource references. And in doing so pretty much negates the readability argument.

Slappy
  • 4,042
  • 2
  • 29
  • 41
  • I revised the code samples to give camp 1 a fairer representation. In general, I have selected a bad example, but I have still received lots of good feedback, so thank you! – Kimberly Mar 31 '11 at 05:13
0

+1 for Camp 2.

Your Camp 1 sample disposes objects that could be used AFTER beeing disposed. I think it is not a problem with your exact scenario, but could be problem with other cases. Camp 2 version forces you to dispose objects in properly nested scopes making code safe.

Sample:

StreamWriter writer;
using(var stream = new FileStream(name))
{
    writer = new StreamWriter(stream);
}
writer.Write(1); // <= writnig to closed stream here.
writer.Dispose();
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Thanks. This seems like an important point, though you are the only one making it so far. I think my question was worth asking, but my example was not so good. If I had known that DataTable does not need to be disposed, I would have used a better example - something like this, maybe. Except that in this case it is not a question of which way is better: this code is never valid. If Camp 1 advocates for it, they are definitely wrong, not just 'less right'. – Kimberly Mar 31 '11 at 04:32
0

Your Camp 1 example is a bit of a Straw Man, it doesn't have to be as ugly as that.

If performance was an issue (which is probably rare, and unlikely in this contrived example), I would go for a cleaner version of "Camp 1" by refactoring the generation of the DataTable into a method:

private DataTable GetDataTableFromInHouseAdapter()
{
    using (InHouseDataAdapter inHouseDataAdapter = new InHouseDataAdapter())
    using (SqlCommand cmd = new SqlCommand())
    {
        return inHouseDataAdapter.GetDataTable(cmd);
    }
}

...
List<MyObject> listToReturn = new List<MyObject>();
using (DataTable dt = GetDataTableFromInHouseAdapter())
{
    foreach (DataRow dr in dt.Rows)
    {
        listToReturn.Add(new MyObject(dr));
    }
}

This looks more realistic - the method that generates the DataTable belongs in the Data Access Layer, and the transformation to a list of MyObject instances probably belongs in a Facade above the DAL.

In fact I would always consider refactoring a nested using statement into its own method - except when they're closely related (such as SqlConnection/Command, or even InHouseDataAdapter/SqlCommand).

Joe
  • 122,218
  • 32
  • 205
  • 338
  • I agree about the straw man. Believe it or not, the example is real, not contrived, but I would never have used it anyway if I had known that DataTable need not be disposed. (I would have contrived something more fair.) I'm just not sure whether it's appropriate to edit the question heavily at this point. – Kimberly Mar 31 '11 at 04:37
  • Also, I like this method structure better, too, but my organization's standard design patterns don't have as many layers of abstraction as this. I could put the two methods in the same class - pretending an extra layer - but I'm likely to be told to stuff them back together, unless the inner method has at least two callers. – Kimberly Mar 31 '11 at 04:38
  • "...told to stuff them back together, unless the inner method has at least two callers" - that's just pathological, I don't think I'd last long in an environment like that :) – Joe Mar 31 '11 at 05:21
0

Another possible design would be to close the inHouseDataAdapter or SqlCommand within their "Using" blocks, since a proper IDisposable implementation is required to be tolerant of multiple cleanup attempts. In many situations, I think an explicit close/dispose within a Using block can be a good idea, since an explicitly-called Close method may provide more helpful exceptions than IDisposable.Dispose (the arguments against IDisposable.Dispose throwing an exception don't apply to Close methods).

In this particular scenario, I would affirmatively leave the SqlCommand and inHouseDataAdapter open while copying the DataTable to the List, however. If the GetDataTable returns a DataTable that actually holds data, the foreach loop should execute quickly (so the data-supply entities would not be held open excessively long). Only if it returns a lazy-reading DataTable derivative would the foreach loop take awhile to execute, and in that scenario the data-supply entities would probably need to be held open long enough for the loop to complete.

supercat
  • 77,689
  • 9
  • 166
  • 211