C# 的 USING 关键字 - 何时使用,何时不使用?

27

我想知道何时应该和不应该在 USING 代码块中使用。

据我所知,编译器将其转换为 try/finally 代码块,在 finally 语句块中调用对象的 Dispose() 方法。

我通常会在数据库连接和文件访问等情况下使用 USING,但这更多是出于习惯而不是完全理解。我知道您应该显式(或使用 USING)Dispose()控制资源的对象,以确保它们立即释放而不是CLR感觉到的时间,但这就是我的理解止步的地方。

IDisposable 对象是否在其作用域外被处理?

当我的对象利用 Dispose() 来清理自己时,我只需要在 USING 中使用吗?

谢谢。

编辑:我知道有几篇关于 USING 关键字的文章,但我更感兴趣的是与 CLR 相关的答案以及内部实际发生的事情。

安德鲁

3个回答

23
不,当它们超出范围时,IDisposable项目不会被处理。正是因为这个原因,我们需要IDisposable来进行确定性清理。
它们最终将被垃圾回收,并且如果有终结器,它可能会被调用 - 但这可能在未来很长一段时间内发生(对于连接池等并不好)。垃圾回收取决于内存压力 - 如果没有任何东西需要额外的内存,就没有必要运行GC周期。
有趣的是(也许),有些情况下“using”很麻烦 - 当有问题的类在Dispose()上抛出异常时。WCF就是一个罪犯。我已经讨论过这个话题(有一个简单的解决方案)here
基本上 - 如果该类实现了IDisposable,并且您拥有一个实例(即您创建了它或其他什么),则您需要确保它被处理。这可能通过“using”完成,也可能意味着将其传递给另一段代码,该代码承担责任。
我实际上看到过以下类型的调试代码:
#if DEBUG
    ~Foo() {
        // complain loudly that smoebody forgot to dispose...
    }
#endif

(其中Dispose调用GC.SuppressFinalize

如果您使用这种技术,请千万不要忘记添加“#if DEBUG”。我在想JetBrains,以及他们在Visual Studio的终结器队列中有30000个对象... - Will Dean
+1,我希望我能够给予更多的赞:p...在StackOverflow上分享了卓越的知识...真是太棒了... - Mayank Pathak

5

"当IDisposable对象超出范围时,它们是否会被处理?"

不会。如果IDisposable对象是可终结的(finalizable),那么它将在垃圾回收时进行终结处理,但这并不代表它已经被处理了。

这可能很快,也可能几乎永远不会。

Jeff Richter的C#/CLR书籍非常好,包含了所有这些内容,Framework Design Guidelines书籍也很有用。

当我的对象使用Dispose来整理自己时,我是否只需要使用Using?

只有当对象实现IDisposable接口时,才能使用'using'。否则编译器会报错。


2

除了其他答案之外,当一个对象持有除托管内存以外的任何资源时,应该使用using(或显式的Dispose)。例如,文件、套接字、数据库连接甚至GDI绘图句柄等。

垃圾收集器最终会处理这些对象,但只会在未来的某个不确定的时间进行。您不能依赖它及时处理,而且在此期间您可能已经用尽了该资源。


2
可以说,只要类实现了IDisposable接口,就应该简单地使用“using”语句。它的实现细节并不重要 ;-p 只有当你的类封装了非托管资源时,才应该添加finalizer。纯托管代码中也有IDisposable的示例... - Marc Gravell
好评,应该将其作为答案并获得一些投票支持。xx - Andrew Bullock
Marc:你说得对。我想我真的是在试图解释为什么实现者可能会创建一个IDisposable类,而不是垃圾回收解决所有资源管理问题的动机。 - babbageclunk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接