Search code examples
c#idisposableusing-statement

using statement on IDisposable object - delay of calling Dispose method


As describe this article, about usage of using on IDisposable objects, it says one interesting words:

...using block, the Dispose method is automatically called sometime after the block ends. (It may not be immediate; it depends on the CLR.)

Interesting here is "It may not be immediate; it depends on the CLR". Can anyone provide more details on this? Because we have some strange situations where it seems that on code using(new MyDisposable()) {...}, after end of block } it does NOT immediately calls Dispose method on MyDisposable instance, but some time later.

UPDATE: Conclusion for me, it seems to me that i have problem elsewhere. I think that Dispose method can be called some time later after using block ends. But when it is not like that, than i must find problem somewhere else in my code. Thanks for responses!


Solution

  • I'm a little skeptical of that statement, and think they meant something else (perhaps garbage collection). A using statement is just syntactic sugar for a try/finally block where the finally block calls dispose. Given this C#:

    using (var fs = new FileStream("C:\\blah.txt", FileMode.CreateNew))
    {
        fs.WriteByte(7);
    }
    

    The IL looks like this:

    //snipped
    L_000e: nop 
    L_000f: ldstr "C:\\blah.txt"
    L_0014: ldc.i4.1 
    L_0015: newobj instance void [mscorlib]System.IO.FileStream::.ctor(string, valuetype [mscorlib]System.IO.FileMode)
    L_001a: stloc.0 
    L_001b: nop 
    L_001c: ldloc.0 
    L_001d: ldc.i4.7 
    L_001e: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8)
    L_0023: nop 
    L_0024: nop 
    L_0025: leave.s L_0037
    L_0027: ldloc.0 
    L_0028: ldnull 
    L_0029: ceq 
    L_002b: stloc.1 
    L_002c: ldloc.1 
    L_002d: brtrue.s L_0036
    L_002f: ldloc.0 
    L_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_0035: nop 
    L_0036: endfinally 
    L_0037: nop 
    L_0038: nop 
    L_0039: ret 
    .try L_001b to L_0027 finally handler L_0027 to L_0037
    

    Notice on the last line it's just a .try and .finally. This is also indicated in The using statement from the C# spec.