views:

242

answers:

7

I use the using statement for SqlConnection. It's is good for performance because forces calling Dispose() that simply releases the connection to the pool sooner.

However, I realized that object created in using cannot be redefined. I cannot do like this:

   using (SqlConnection connection = new SqlConnection(connectionString))
   {
       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
   }

I was wondering if I can replace using, and do something like this:

 {
       SqlConnection connection = new SqlConnection(connectionString);

       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
 }

The SqlConnection will not be accesible after last } brace. Will be the Dispose() called immediatly when object goes out of scope?

+3  A: 

No, using creates some specific clean-up constructs that you won't get with just the braces.

If you use Reflector and look at the IL there's a call to Dispose added at the end of the using block for its target:

    L_0006: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)
L_000b: stloc.0 
L_000c: nop 
L_000d: nop 
L_000e: leave.s L_0020
L_0010: ldloc.0 
L_0011: ldnull 
L_0012: ceq 
L_0014: stloc.1 
L_0015: ldloc.1 
L_0016: brtrue.s L_001f
L_0018: ldloc.0 
**L_0019: callvirt instance void [mscorlib]System.IDisposable::Dispose()**
L_001e: nop 
L_001f: endfinally 

This explains why you can't create a new connection inside the using block and assign it to the variable -- doing so would leave the original reference hanging and undisposed.

Ragoczy
I think it calls Dispose() on IDisposable objects... don't know for sure
Mike Gleason jr Couturier
@Mike - You can only use `using` on IDisposable objects because it calls Dispose()
annakata
It actually calls `((IDisposable) blah).Dispose()`, where `blah` is the using variable. It doesn’t compile if the type doesn’t implement `IDisposable`.
Timwi
Thanks for both clarifications!
Mike Gleason jr Couturier
+3  A: 

No, it won't be called after the closing curly brace. You need to call it manually or use a using statement.

If you don't execute the dispose then It will be executed when the finalize is called. And here you have 2 problems

  • Executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method (if it's well implemented, a Dispose method should call the SuppressFinalize method for the object it is disposing). (MSDN)
  • You don't control the moment when the finalize is automatically called and could not be executed (because a crash for instance).
Claudio Redi
+8  A: 

The using statement is syntactic sugar that calls Dispose on the objects initialized within the (), so you can't simply replace it as you have in your example.

You will note that the only objects that you can use within a using statement are those that implement IDisposable, which ensures that Dispose can be called.

As this article explains, the compiler will transform this:

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();

}

To this:

MyResource myRes= new MyResource();
try
{
    myRes.DoSomething();
}
finally
{
    if (myRes!= null)
        ((IDisposable)myRes).Dispose();
}

So, unless you duplicate this structure, you won't get the same behavior.

In addition - reusing a variable the way you are in your example is bad practice. Someone who reads the code may think they are looking at connection 1 when they are in fact looking at 2 or 3. Could end up very confusing and cause all kinds of problems down the road.

Oded
Well I tried to get rid of usings because I have a lot of them (I also use them frequently with 'Streams' in my project). The second reason is that I have a lot of sequential connections so I thought about using one object. I wanted to increase legibility but you're right it may just decrease it.
Andrzej Nosal
+13  A: 

No, things won't get automatically cleaned up in your second example (in fact, with the code you have, you'll leave several connections hanging open).

Not only that, but you lose the automatic cleanup in case of Exceptions being thrown inside the using block. Remember that a using block decomposes into:

SqlConnection connection = new SqlConnection(connectionString);
try
{
    connection.Open();
    // Do work
}
finally
{
    connection.Dispose();
}

If you're really using different connections and each connection is Disposed of at the end of the block, I would use several using blocks:

using(SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    // Do Work
}

// First connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString2))
{
    // Do More Work
}

// Second connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString3))
{
    // Do More Work
}

// Last connection is dipsosed
Justin Niessner
Thanks. If it comes to closing connections I would of course call connection.Close() but I didn't write it in the code above.
Andrzej Nosal
Even if you call Close() explicitly, your second example still has the potential to leave a connection open if an exception occurs. Not only does using call Dispose when execution leaves that block, it also calls it when an exception occurs.
ThatBlairGuy
+3  A: 
using(foo)
{
  // stuff
}

...is a bit of sugar which translates into:

try
{
  // stuff
}
finally
{
  foo.Dispose()
}

Whereas:

{
  // stuff
}

...doesn't translate into anything. It's just:

{
  // stuff
}

:D

Edit: Please don't destroy formatting when you edit :(

annakata
+2  A: 

No, you can't do this. At least in C#.

But you can create different disposable objects inside one using statement:

   using (SqlConnection connection1 = new SqlConnection(connectionString1),
          connection2 = new SqlConnection(connectionString2),
          connection3 = new SqlConnection(connectionString3))
   {
       connection1.Open();
       //...
       connection2.Open();
       //...
       connection3.Open();
   }

C++/CLI you may use your disposable classes in stack-like faision:

void MyClass::Foo()
{

{
  SqlConnection connection(connectionString);
  //connection still allocated on the managed heap
  connection.Open();
  ...
  //connection will be automatically disposed 
  //when the object gets out of scope
} 


{
  SqlConnection connection(connectionString2);
  connection2.Open();
  ...
}

}
Sergey Teplyakov
+1 for nice 'usings' grouping, didn't know about that
Andrzej Nosal
+1  A: 

I thought this too at first... but apparently when the using block ends, .Dispose() is called on your object, which is different than letting the object go out of scope. Because C# is a garbage collected language, it could take time before your object is actually cleaned up. The using block ensures that it is disposed of immediately, and regardless of any exceptions.

Mark