c# - IDisposable:是否有必要在 finally {} 上检查 null?

标签 c# .net idisposable coding-style

在您在网络上找到的大多数明确不使用“使用”的示例中,模式类似于:

  SqlConnection c = new SqlConnection(@"...");
  try {
    c.Open();
  ...
  } finally {
    if (c != null) //<== check for null
      c.Dispose();
  }

如果您使用“using”并查看生成的 IL 代码,您可以看到它生成了 null 的检查

L_0024: ldloc.1 
L_0025: ldnull 
L_0026: ceq 
L_0028: stloc.s CS$4$0000
L_002a: ldloc.s CS$4$0000
L_002c: brtrue.s L_0035
L_002e: ldloc.1 
L_002f: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_0034: nop 
L_0035: endfinally 

我理解为什么 IL 被翻译为检查 null(不知道你在 using block 中做了什么),但是如果你使用 try..finally 并且你可以完全控制 IDisposable 对象的使用方式在 try..finally block 中,您真的需要检查 null 吗?如果是,为什么?

最佳答案

“using”语句可以使用构造函数以外的调用来初始化变量。例如:

using (Foo f = GetFoo())
{
    ...
}

此处 f 很容易为 null - 而构造函数调用永远不会1 返回 null。这就是 using 语句检查无效性的原因。这与 block 本身内部的内容无关,因为 using 语句保留了原始初始值。如果你写:

Stream s;
using (s = File.OpenRead("foo.txt"))
{
    s = null;
}

那么流仍然会被释放。 (如果变量在 using 语句的初始化部分声明,则无论如何它都是只读的。)

在你的情况下,正如你知道 c 在你进入 try block 之前是非空的,你不需要在 finally block ,除非你在 block 内重新分配它的值(我真诚地希望你不是!)。

现在,对于您当前的代码,在分配给 c 和进入 try 之间可能抛出异步异常的轻微风险 block - 但很难完全避免这种竞争条件,因为在构造函数完成之后但在将值分配给 c 之前同样可能存在异步异常。我建议大多数开发人员不需要担心这类事情 - 异步异常往往足够“困难”,以至于他们无论如何都会降低进程。

你有什么理由不想只使用 using 语句吗?老实说,这些天我很少自己写 finally block ......


1 看到Marc的回答哭了。虽然通常不相关。

关于c# - IDisposable:是否有必要在 finally {} 上检查 null?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2597837/

相关文章:

.net - 在这种情况下,.Net 会为我调用 Dispose 吗?

c# - 我们什么时候应该为组件实现带有 IContainer 参数的构造函数?

c# - 使用 linq 和 lambda 表达式简化传统的 foreach 嵌套循环

c# - 如何使用 20 字节 key 进入 AES ECB 模式

.net - 如何跨同一个域但不同的主机共享本地存储 token ?

javascript - 计算 Ajax 请求中返回的对象数量

.net - 发布 ASP.NET 应用程序时,是否应该在 Visual Studio 配置管理器中将构建类型更改为发布?

c# - 使用匹配的 xsd 文件创建自定义配置文件 - 实现一个类

c# - 数组索引可以在 C# 中命名吗?

entity-framework-4 - 处理 ObjectResult<T>