在您在网络上找到的大多数明确不使用“使用”的示例中,模式类似于:
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/