为什么 using(null) 在 C# 中是有效的情况?

发布于 2024-10-20 06:37:30 字数 890 浏览 1 评论 0原文

有人可以向我解释为什么下面显示的代码在 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()?是否存在其他情况下编译器可能决定不在 using 块中调用 Dispose()

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为你拒绝所有暧昧 2024-10-27 06:37:30

语言规范明确指出(8.13),如有必要,捕获的值将被测试为空,即 finally 本质上是(对不可为空类型的警告)

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

我经常使用它来发挥我的优势,因为可能为空,但如果不是:需要处置。事实上,这是一个有用的场景(手动枚举 IEnumerable):

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

因为 IEnumerator 的非泛型版本不一定是 IDisposable,但是当是的,应该处理掉。

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.

脱离于你 2024-10-27 06:37:30

我认为这是 using(some_expression) 更一般情况的自然结果,其中 some_expression 允许计算为 null

需要制定一项特殊规则来区分这种情况与更一般的情况。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文