有人可以向我解释为什么下面显示的代码在C#中有效并执行对Console.WriteLine
的调用吗?
using (null)
{
Console.WriteLine ("something is here")
}
编译成(最后显示块)。如您所见,编译器决定不执行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
但是,如果我运行以下代码,它将失败并显示NullReferenceException
(预期):
((IDisposable)null).Dispose();
IL_0023: ldnull
IL_0024: callvirt instance void [mscorlib]System.IDisposable::Dispose()
为什么第一个版本会编译?为什么编译器决定不执行Dispose()
?当编译器决定不在Dispose()
块中调用using
时,是否还有其他情况?
答案 0 :(得分:12)
语言规范明确指出(8.13)在必要时测试捕获的值是否为null,即finally
本质上是(围绕非可空类型的警告)
if(tmp != null) tmp.Dispose();
我经常使用这个对我有利,对于可能为空的东西,但是当它们不是时:需要处理。实际上,这是一个有用的场景(手动枚举IEnumerable
):
IEnumerable blah = ...; // note non-generic version
IEnumerator iter = blah.GetEnumerator();
using(iter as IDisposable)
{
// loop
}
由于IEnumerator
的非通用版本不一定是IDisposable
,但如果是,则应予以处理。
答案 1 :(得分:1)
我认为这是using(some_expression)
的更一般情况的自然结果,其中some_expression
is allowed to evaluate to null
。
这需要一个特殊的规则来区分这种情况和更普遍的情况。
答案 2 :(得分:0)
如果Object为null,它将忽略 - http://msdn.microsoft.com/en-us/library/yh598w02.aspx