嗯,它不会被丢弃,因为终结(finalisation)不是处理处置(disposal)。
System.ComponentModel.Component
中有一个终结器(finaliser),但在SQLConnection
的构造函数中被禁止。如果您从具有终结器的东西继承并且您100%确定您不需要它,则这是一个好主意,否则就不是一个好主意。在这种情况下,这是一个好主意。
请记住,SqlConnection
是“真实”连接的包装器。实际上,它很可能是对表示不同连接状态的不同对象集的包装器。这是允许有效地池化“真实”连接的机制的一部分,每次调用Open()
时,它都会从池中获取相关对象,并且每次调用Close()
(无论是直接,通过Dispose()
还是通过离开using
的作用域)都会将其返回。
现在,请记住,只有直接持有未管理资源或其他GC不关心的内容的对象才需要进行终结。 SqlConnection
持有一个对象,该对象可能(取决于SqlConnection
的状态)是一个持有未受管资源的对象(或者更深层次的嵌套类)。因此,SqlConnection
本身无需进行终结。考虑一个开放的SqlConnection
可能停止成为开放的SqlConnection
的三种可能方式:
- 调用
Close()
。这将立即将实际连接返回到池中(如果没有汇集,则关闭)。
- 调用
Dispose()
。这将调用具有相同效果的Close()
。
- 对象被垃圾回收。
现在,在第三种情况下,这个对象持有一个对真实连接对象的引用。它也是唯一持有该引用的对象。由此,该对象也将被垃圾回收。如果它有一个终结器(它可能有,虽然我不会假设没有更多聪明的技巧),那么这个终结器将导致它被放入终结器队列中,并最终完成终结操作。
如果
SqlConnection
有一个终结器,那么唯一的真实影响将是:
- 潜在的错误代码(在终止代码中处理可终结成员是很危险的,因为你不知道它们是否已经终结)。
- 潜在的减速(真实连接终结的结果是相同的,最好的情况只是减缓了终结和GC的过程)。
- 无事可做(真实连接将在没有任何帮助的情况下进行终结)。
因此,在
SqlConnection
上放置终结器是得不偿失的。而且,您的真实连接应该会最终完成终结。
话虽如此,这仍然远非理想状态,仍然非常可能泄漏连接。您能详细说明为什么不能调用
Close()
或自行处理吗?连接管理代码不能为您调用关闭操作吗(对象应该在某处结束其生命周期,并在那里关闭)?
是否需要将其保持活动状态以允许完成
IDataReader
或从
IDataReader
输入的对象?如果是这种情况,您可以使用
CommandBehavior.CloseConnection
标志,使关闭 (或处理) 读取器时关闭连接。后者是我唯一能想到必须让连接离开作用域而不被处理的情况。
SqlConnection
类确实是托管对象,它通过一些托管层次的间接方式包装了执行实际的 1 和 0 传输的非托管对象。是的,在 finaliser 中永远不要处理(除非你知道该托管对象应该具有自己的 finaliser 但实际上没有)。通常这样做会干扰该对象的 finaliser,并且也应该是不必要的,因为该其他对象中已经有了 finaliser。 - Jon Hanna