调用Dispose()vs对象超出范围/方法完成

时间:2009-12-02 13:41:14

标签: c# idisposable using using-statement

我有一个方法,里面有一个try/catch/finaly块。在try块中,我声明SqlDataReader如下:

SqlDataReader aReader = null;          
aReader = aCommand.ExecuteReader();

finally块中,手动处理的对象是在类级别设置的对象。因此,实现IDisposable的方法中的对象(例如上面的SqlDataReader)是否会被自动处理?执行while循环后,Close()会调用aReader以获取阅读器的内容(调用Dispose()时应为Close())。如果没有调用Close(),当方法完成或对象超出范围时,是否会自动关闭/处置此对象?

编辑:我知道using声明,但有些情况令我感到困惑。

6 个答案:

答案 0 :(得分:25)

不,当对象超出范围时,对象不会自动处理。

如果/当他们被垃圾收集时,他们甚至不能保证被处置,尽管许多IDisposable对象实施了“后备”终结器以帮助确保他们最终被处置。

您有责任确保处置任何IDisposable个对象,最好将它们包裹在using块中。

答案 1 :(得分:8)

您应该使用using {...}块来包装您的IDisposable对象 - 当使用块结束时,将调用Dispose()方法(对于SqlDataReader传递给Close()方法) 。如果你不使用using,那么当对象超出范围时,会被自动处理 - 它将取决于对象终结器,如果它有一个,可以去除垃圾收集时的资源

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // ... do stuff
}   // aReader.Dispose() called here

答案 2 :(得分:1)

Dispose模式不保证哪些对象将调用Dispose来处理其他对象;它有时会发生,但你不应该在乎。相反,您有责任确保为所有IDisposable对象调用Dispose()。最好的方法是使用using语句。例如:

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // your code
}

答案 3 :(得分:1)

我同意以上所有内容。您应确保自己致电Dispose(),最简单的方法是使用using语句(您也可以在finally块中自行完成此操作 - 这更详细,但有时是必要的)。如果你不这样做,你会发现你的应用程序泄漏了非托管资源,如句柄,甚至非托管内存,特别是如果正在使用所有这些COM组件下面的某个地方,或者正在调用Win32 API。这显然会导致性能和稳定性问题,以及过多的资源使用。

仅仅因为实现IDisposable的对象“应该”实现调用其Dispose(bool disposing)方法来释放非托管资源的终结器,并不能保证会发生这种情况,所以你绝对不应该依赖它。例如,有关此点的更多信息,请参阅http://msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspx

另外,要记住的是,如果您的类型具有一次性成员,则您的类型应该实现IDisposable(除非这些成员的生命周期由另一种类型管理,显然可能会获得(如果你只在一种方法中使用这些成员,或者实现一个特定的功能),你应该考虑在使用它们的方法中将它们作为局部变量/参数。

答案 4 :(得分:0)

我对这句话感到困惑“在finally块中,手动处理的对象是那些在类级别设置的对象。”通过在类级别设置的对象,您的意思是字段吗?您可能不应该在普通方法中处理这些,因为那时字段的生命周期是不可预测的,并且取决于您碰巧调用的方法。最好在Dispose方法中实现IDisposable和处理字段。

答案 5 :(得分:-2)

Using语句有帮助吗?