Using statement vs. IDisposable.Dispose()
C#.Netvb.netUsingIdisposableC# Problem Overview
It has been my understanding that the using
statement in .NET calls an IDisposable
object's Dispose()
method once the code exits the block.
Does the using
statement do anything else? If not, it would seem that the following two code samples achieve the exact same thing:
Using Con as New Connection()
Con.Open()
'do whatever '
End Using
Dim Con as New Connection()
Con.Open()
'do whatever '
Con.Dispose()
I will give the best answer to whoever confirms that I am correct or points out that I am wrong and explains why. Keep in mind that I am aware that certain classes can do different things in their Dispose()
methods. This question is about whether or not the using
statement achieves the exact same result as calling an object's Dispose()
method.
C# Solutions
Solution 1 - C#
using
is basically the equivalent of:
try
{
// code
}
finally
{
obj.Dispose();
}
So it also has the benefit of calling Dispose()
even if an unhandled exception is thrown in the code within the block.
Solution 2 - C#
As Brian Warshaw stated in here it's simply an implementation of try
and finally
block to make sure object is disposed. Adding to his answer, using
block also makes sure that the object is disposed even if you return inside using scope.
I was once curious about this myself and tested it out using the following approach:
Custom IDisposable test class and Main
private class DisposableTest : IDisposable
{
public string Name { get; set; }
public void Dispose() { Console.WriteLine("{0}.Dispose() is called !", Name); }
}
public static void Main(string[] args)
{
try
{
UsingReturnTest();
UsingExceptionTest();
}
catch { }
try
{
DisposeReturnTest();
DisposeExceptionTest();
}
catch { }
DisposeExtraTest();
Console.ReadLine();
}
Test cases implementation
private static string UsingReturnTest()
{
using (DisposableTest usingReturn = new DisposableTest() { Name = "UsingReturn" })
{
return usingReturn.Name;
}
}
private static void UsingExceptionTest()
{
using (DisposableTest usingException = new DisposableTest() { Name = "UsingException" })
{
int x = int.Parse("NaN");
}
}
private static string DisposeReturnTest()
{
DisposableTest disposeReturn = new DisposableTest() { Name = "DisposeReturn" };
return disposeReturn.Name;
disposeReturn.Dispose(); // # IDE Warning; Unreachable code detected
}
private static void DisposeExceptionTest()
{
DisposableTest disposeException = new DisposableTest() { Name = "DisposeException" };
int x = int.Parse("NaN");
disposeException.Dispose();
}
private static void DisposeExtraTest()
{
DisposableTest disposeExtra = null;
try
{
disposeExtra = new DisposableTest() { Name = "DisposeExtra" };
return;
}
catch { }
finally
{
if (disposeExtra != null) { disposeExtra.Dispose(); }
}
}
And the output is:
- UsingReturn.Dispose() is called !
- UsingException.Dispose() is called !
- DisposeExtra.Dispose() is called !
Solution 3 - C#
//preceeding code
using (con = new Connection()) {
con.Open()
//do whatever
}
//following code
is equivalent to the following (note the limited scope for con):
//preceeding code
{
var con = new Connection();
try {
con.Open()
//do whatever
} finally {
if (con != null) con.Dispose();
}
}
//following code
This is described here: http://msdn.microsoft.com/en-us/library/yh598w02.aspx
> The using statement ensures that Dispose is called even if an > exception occurs while you are calling methods on the object. You can > achieve the same result by putting the object inside a try block and > then calling Dispose in a finally block; in fact, this is how the > using statement is translated by the compiler.
Solution 4 - C#
A using
statement is clearer and more concise than a try...finally{Dispose()}
construct, and should be used in nearly all cases where one does not want to allow a block to exit without Dispose
being called. The only common situations where "manual" disposal would be better would be when:
- A method calls a factory method which returns something that may or may not implement
IDisposable
, but which should beDispose
d if it does (a scenario which occurs with non-genericIEnumerable.GetEnumerator()
). Well-designed factory interfaces should either return a type that implementsIDisposable
(perhaps with a do-nothing implementation, as is typically the case ofIEnumerator<T>
) or else specify callers are not expected toDispose
the returned object. Unfortunately, some interfaces like non-genericIEnumerable
satisfy neither criterion. Note that one cannot very well useusing
in such cases, since it only works with storage locations whose declared type implementsIDisposable
. - The
IDisposable
object is expected to live even after the block is exited (as is often the case when setting anIDisposable
field, or returning anIDisposable
from a factory method).
IDisposable
from a factory method, one should use something like the following:
bool ok = false; DisposableClass myThing; try { myThing = new DisposableClass(); ... ok = true; return myThing; } finally { if (!ok) { if (myThing != null) myThing.Dispose(); } }to ensure that
myThing
will get Dispose
d if it doesn't get returned. I wish there was a way to employ using
along with some "cancel Dispose" method, but no such thing exists.
Solution 5 - C#
The difference between the two is that, if an Exception is thrown in
Con.Open()
'do whatever
Con.Dispose
will not be called.
I'm not up on VB syntax, but in C#, the equivalent code would be
try
{
con = new Connection();
// Do whatever
}
finally
{
if (con != null) con.Dispose();
}
Solution 6 - C#
The using block makes sure that Dispose()
is called if an exception is thrown.
Your second sample does not do that.
If Con.Open()
threw an exception, in the first case you are guaranteed that Con.Dispose()
is called. In the second case, the exception propagates up and Con.Dispose()
will not be called.
Solution 7 - C#
The using
statement guarantees that the object is disposed in the event an exception is thrown. It's the equivalent of calling dispose in a finally
block.
Solution 8 - C#
Using wraps the enclosed block in a try/finally that calls Dispose in the finally block. This ensures that Dispose will be called even if an exception occurs.
You should use using in almost all cases, for safety reasons
Solution 9 - C#
If memory serves, using is a guarantee that an object is disposed of regardless of how the block of code it surrounds exits it. It does this by surrounding the block in a try...finally block, and checking the used variable for nullness, and then disposing of it if it is not null. If an exception was thrown, it's allowed to bubble up the stack. Aside from that, all it does is guarantee disposal of non-null disposable objects.
try
{
var myDisposable = new DisposableObject();
myDisposable.DoSomething();
}
finally
{
if (myDisposable != null)
((IDisposable)myDisposable).Dispose();
}