我想知道,如果可能的话,如何检测垃圾收集器是否处理了SqlConnection,因为它发现它不再使用,或者SqlConnection是否正确关闭。
另一种方法可能是继承SqlConnection,并在其初始化程序上放置一个计时器,并在处理类时检查连接关闭需要多长时间。我不太喜欢计时器,但这个想法只是在写这篇文章时出现的。
也许有第三种更聪明的方法...你会推荐什么?
由于SqlConnection是密封的,您将无法从它继承。(而且我认为这样做不是一个好主意--如果可能的话,您应该在Dispose(false)中添加代码,因为这是终结器调用的内容)。
更好的方法是使用静态代码分析工具来检测这些问题,该工具有能力检测您的代码中所有忘记释放连接的地方。Visual Studio内置了一个(链接1),或者您可以使用FxCop。
为了帮助您不要忘记释放连接,建议您:
有一条经验法则是,“如果你必须考虑垃圾收集器,那么你可能做错了什么。”(当然,还有其他的方法...)
在我看来,确保连接被明确关闭或通过using
和finally
块关闭是最好的方法。
显然,您已经了解了这些技术...所以也许只需要浏览一遍代码并进行可能的重构。
http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx
回答你的问题,我不认为有一个GC收集的事件,但即使有也无所谓,因为你永远不会知道GC是否选择在那个收集过程中回收你的对象(并非所有对象都因为分代算法而被清理)。如果您忘记释放,对象将被终结。没有办法控制它发生的时间,也没有办法知道对象是否已经被终结。必须创建一个单独的线程来终结对象,因此会减慢应用程序的速度。这就是为什么您需要释放资源。在框架中实现IDisposable接口的所有类都会调用GC.SuppressFinalize方法,以便对象不会被终结。
您无法控制此行为。如果您的对象不再使用,它将自动被收集。您唯一能做的是调用GC.SuppressFinalize来停止这个过程,但我不建议这样做,因为如果您忘记了,那么您将会遭受终身的损失。
您可以创建一个包装类(而不是子类),在您的代码中使用它提供的一些简单方法来始终调用Dispose。否则,请确保检查得非常仔细。
首先,如果您甚至考虑使用GC,那么您肯定有严重的问题。我建议您使用诸如模拟之类的技术对代码进行单元测试,以确保您的代码调用了Close。如果您的单元测试表明已经调用了Close,则您的代码是正确的,您不必做任何不必要的危险操作,比如搞乱垃圾回收器。
其次,如果您仍然坚持采用运行时检查路线,那么您唯一需要考虑的事情就是挂钩SqlConnection
的StateChange
事件。例如,当ConnectionState从Open变为Closed时,它将触发。