为什么在C#中使用(null)有效的案例?

And*_*nov 10 .net c# using-statement

有人可以向我解释为什么下面显示的代码在C#中有效并执行调用Console.WriteLine

using (null) 
{
   Console.WriteLine ("something is here")
}
Run Code Online (Sandbox Code Playgroud)

它编译成(最后显示块).如您所见,编译器决定不执行该Dispose()方法并跳转到该endfinally指令.

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
Run Code Online (Sandbox Code Playgroud)

但是,如果我运行以下代码,它将失败a NullReferenceException(预期):

((IDisposable)null).Dispose();
IL_0023:  ldnull
IL_0024:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
Run Code Online (Sandbox Code Playgroud)

为什么第一个版本编译?为什么编译器决定不执行Dispose()?是否有任何其他情况下,当编译器可以决定不叫Dispose()using块?

Mar*_*ell 13

语言规范明确指出(8.13)在必要时测试捕获的值是否为null,即finally基本上(对于非可空类型的警告)

if(tmp != null) tmp.Dispose();
Run Code Online (Sandbox Code Playgroud)

我经常使用这个对我有利,对于可能为空的东西,但是当它们不是时:需要处理.实际上,这是一个有用的场景(手动枚举IEnumerable):

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

因为非通用版本IEnumerator不一定IDisposable,但是当它是,应该被处置.