61

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.

DavidRR
  • 18,291
  • 25
  • 109
  • 191
oscilatingcretin
  • 10,457
  • 39
  • 119
  • 206
  • This is excellent advice. My problem was different but I am using the USING statement all the time because it has excellent memory management characteristics. Cheers! – pianocomposer Sep 01 '22 at 21:54

9 Answers9

87

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.

Brian Warshaw
  • 22,657
  • 9
  • 53
  • 72
  • And yes, I know I posted C# and not VB, but hopefully you can translate :-) – Brian Warshaw Jun 11 '12 at 16:53
  • c# is my preferred .NET language, but I was typing out my example in a VB.NET app. Also, this example and answer is exactly what I was looking for. – oscilatingcretin Jun 11 '12 at 16:56
  • 1
    You should have a null check for `obj` before calling `obj.Dispose()`. It may not ever have been assigned as a result of the exception being thrown. – Eric J. Aug 14 '16 at 19:42
  • 3
    @EricJ., this answer isn't a solution to a programming problem--it's a bare-bones explanation of what happens when you make use of the `using` statement and block. – Brian Warshaw Aug 15 '16 at 13:18
  • It also calls close() on objects that are holding connections – jnoreiga Dec 19 '16 at 19:38
21

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 !
Blacky Wolf
  • 429
  • 6
  • 12
Saro Taşciyan
  • 5,210
  • 5
  • 31
  • 50
10
//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.

6

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();
}
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • 3
    Your code is borken. The finalizer will bomb when the Connection constructor throws an exception, "con" is null. Move it out of the try block. The *using* statement also makes sure that re-assigning the variable won't cause trouble. – Hans Passant Jun 11 '12 at 17:58
  • @HansPassant: The normal pattern is to have the assignment within the `try` block, but have the `finally` block test for `null`. If the assignment occurs *immediately* before the `try`, the risk of something like `ThreadAbortException` hitting between the constructor and the assignment is the same regardless of whether the assignment is inside or outside the `try`, but putting it inside the `try` avoids the possibility that code might be added between the assignment and the `try`, which would increase the danger of the object being constructed but not assigned. Having the constructor... – supercat Jun 12 '12 at 14:42
  • @HansPassant: ...take a `ref` parameter might further mitigate that risk, but it would be probably considered an unusual pattern (it would increase the likelihood that a failed constructor would expose an incomplete object, but in some cases exposing an incomplete object and having it get `Dispose`d would be better than having the object disappear and not get `Dispose`d. – supercat Jun 12 '12 at 14:45
  • 1
    No, that's not the normal pattern. And not the way the *using* statement works either. Look at the code the compiler generates with ildasm.exe, note the `.try` *after* the constructor call. – Hans Passant Jun 12 '12 at 14:48
  • Thanks for that, I hadn't known about ildasm until now. I checked it myself when using StreamWriter in a using block. Before the .try, it calls **[mscorlib]System.IO.StreamWriter** and allocates it, _then_ the **try** starts. – kayleeFrye_onDeck Feb 12 '15 at 19:13
6

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:

  1. A method calls a factory method which returns something that may or may not implement `IDisposable`, but which should be `Dispose`d if it does (a scenario which occurs with non-generic `IEnumerable.GetEnumerator()`). Well-designed factory interfaces should either return a type that implements `IDisposable` (perhaps with a do-nothing implementation, as is typically the case of `IEnumerator`) or else specify callers are not expected to `Dispose` the returned object. Unfortunately, some interfaces like non-generic `IEnumerable` satisfy neither criterion. Note that one cannot very well use `using` in such cases, since it only works with storage locations whose declared type implements `IDisposable`.
  2. The `IDisposable` object is expected to live even after the block is exited (as is often the case when setting an `IDisposable` field, or returning an `IDisposable` from a factory method).

Note that when returning an 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 Disposed 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.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • I've used a variation of this is a few places of my code. I use catch -> dispose -> throw instead of the finally with a boolean. Do you have any info if they are equivalent, or if one is better than the other? – julealgon Aug 21 '14 at 14:28
  • I favor doing such cleanup in `finally`, for a couple of reasons: (1) If some unconditional cleanup code should run before the failure-only cleanup code, such a sequence will fit nicely in the pattern [simply put it before the `if(!ok)`; (2) the semantics of catching and rethrowing an exception is different from not catching it. Among other things: (1) Catching and rethrowing an exception will cause all inner `finally` blocks to run before the exception is rethrown. If a "try, catch, and rethrow" block contains two calls to the same method, and one throws an exception... – supercat Aug 21 '14 at 15:55
  • ...the stack trace will show the line number of the rethrow, rather than the line number of the method call which failed. Further, if an outer block uses an exception filter (possible in VB.NET, and probably the next version of C#), a breakpoint in that filter would make it possible to examine the state of the system before stack unwinding. That can be very helpful in cases where a certain exception would be semi-expected in some parts of the code (and thus shouldn't stop the debugger) but not in others (and thus should). – supercat Aug 21 '14 at 15:58
  • Shouldn't `ok` be set to `true` immediately after `myThing`'s instantiation, since any code in `...` could cause an exception (which would currently leave `ok = false`, preventing `Dispose` from be called)? – samus Aug 12 '16 at 20:45
  • @SamusArin: If `ok` is true, the caller will receive the object and can be expected to dispose of it (it would generally be pointless to `Dispose` an object before returning it). The `ok==false` scenario is the one where the factory function has to dispose of the object because the caller won't get the object and thus can't *possibly* dispose of it. – supercat Aug 12 '16 at 20:50
  • @supercat Oh man I was thinking that the object was done with by the end of the try's scope (for some reason). It is clearly returning. So it is the GC's responsibility from there on out (after the return)? Does the GC call Finalize or Dispose? How does that work? Thanks. – samus Aug 12 '16 at 21:04
  • 1
    @SamusArin: The GC won't call `Dispose`; it might call `Finalize`, but that should generally be considered unreliable. The proper pattern is generally to ensure that for every `IDisposable` object there is--as close to "always" as possible--either one clearly-identifiable entity which is responsible for calling `Dispose` on it, or one live execution context which will call `Dispose` when it exits. Until the above factory function exits, it will have responsibility for calling `Dispose`; once `ok` is set to `true` the caller will have responsibility. – supercat Aug 12 '16 at 21:13
  • 1
    It might be cleaner to say that the caller would always have the responsibility except for one problem: if a factory function throws an exception, the caller won't receive a reference to the partially-constructed object and thus won't be able to dispose of it. Having a function which takes a reference to the object under construction as an `out` parameter might be a better pattern, since it could then ensure the (possibly partially-constructed) object's disposal even if construction fails, but such a pattern would make `using` blocks awkward. – supercat Aug 12 '16 at 21:15
3

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.

jglouie
  • 12,523
  • 6
  • 48
  • 65
3

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.

jrummell
  • 42,637
  • 17
  • 112
  • 171
3

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

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
1

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();
}
Mike Hofer
  • 16,477
  • 11
  • 74
  • 110