13

Could someone please explain to me why the code shown below is valid in C# and executes the call to Console.WriteLine?

using (null) 
{
   Console.WriteLine ("something is here")
}

It compiles into (finally block is shown). As you can see compiler decides not to execute the Dispose() method and jumps to the endfinally instruction.

IL_0013:  ldnull
IL_0014:  ceq
IL_0016:  stloc.1
IL_0017:  ldloc.1
IL_0018:  brtrue.s   IL_0021 // branches here and decide not to execute Dispose()
IL_001a:  ldnull
IL_001b:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
IL_0020:  nop
IL_0021:  endfinally

However, if I run the following code, it will fail with a NullReferenceException (which is expected):

((IDisposable)null).Dispose();
IL_0023:  ldnull
IL_0024:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()

Why does the first version compile? Why does the compiler decide not to execute Dispose()? Are there any other cases when compiler may decide not to call Dispose() in a using block?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Andrey Taptunov
  • 9,367
  • 5
  • 31
  • 44

3 Answers3

17

The language spec explicitly states (8.13) that the captured value is tested for null if necessary, i.e. the finally is essentially (with caveats around non-nullable types)

if(tmp != null) tmp.Dispose();

I frequently use this to my advantage, for things that might be null, but when they aren't: need disposing. In fact, here's a useful scenario (manually enumerating IEnumerable):

IEnumerable blah = ...; // note non-generic version
IEnumerator iter = blah.GetEnumerator();
using(iter as IDisposable)
{
    // loop
}

as the non-generic version of IEnumerator isn't necessarily IDisposable, but when it is, should be disposed.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

I think it's a natural outcome of the more general case of using(some_expression), where some_expression is allowed to evaluate to null.

It would have required a special rule to distinguish this case from the more general one.

Community
  • 1
  • 1
sbi
  • 219,715
  • 46
  • 258
  • 445
0

It will ignore if the Object is null - http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Anuraj
  • 18,859
  • 7
  • 53
  • 79
  • Where does it say that in the documentation you linked to? A search for `null` on that page returned 0 hits. – Cody Gray - on strike Mar 04 '11 at 08:46
  • 1
    In the remarks section. if (font1 != null) ((IDisposable)font1).Dispose(); – Anuraj Mar 04 '11 at 08:48
  • > A using statement is translated into three parts: acquisition, usage, and disposal. Usage of the resource is implicitly enclosed in a try statement that includes a finally clause. This finally clause disposes of the resource. If a null resource is acquired, then no call to Dispose is made, and no exception is thrown. https://msdn.microsoft.com/en-us/library/aa664736(v=vs.71).aspx – boro Dec 01 '15 at 14:40