调用Dispose()与对象超出范围/方法完成时的区别

15

我有一个方法,其中包含一个 try/catch/finaly 块。在 try 块内部,我声明了一个 SqlDataReader 如下:

SqlDataReader aReader = null;          
aReader = aCommand.ExecuteReader();
finally块中,手动处理的对象是那些在类级别上设置的对象。那么实现了IDisposable接口的方法中的对象(如上面的SqlDataReader)是否会自动被处理呢?在循环执行以获取读取器内容之后,会在aReader上调用Close()方法(应该使用Dispose()方法,因为该方法会调用Close()方法)。如果没有调用Close()方法,当方法完成或对象超出作用域时,此对象是否会被自动关闭/处理?

编辑:我知道using语句,但有一些情况让我感到困惑。

6个回答

28

不,当对象超出其作用域时,并不会自动释放。

即使它们被垃圾回收,也不能保证它们被释放,尽管许多 IDisposable 对象实现了一个“回退”终结器来帮助确保它们最终被释放。

您需要确保释放任何 IDisposable 对象,最好通过将它们包装在一个 using 块中。


9
你应该使用 using {...} 块来包装你的 IDisposable 对象 - 当 using 块结束时,Dispose() 方法 (对于 SqlDataReader 来说,会传递给 Close() 方法) 将被调用。如果你不使用 using,当对象超出范围时它将不会自动释放 - 如果对象有终结器,则需要在垃圾回收时通过终结器来清除资源。
using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // ... do stuff
}   // aReader.Dispose() called here

3
我同意上述所有内容。您应该确保自己调用 Dispose(),最简单的方法是使用 using 语句(您也可以在 finally 块中自己完成 - 这更加冗长,但有时是必要的)。如果不这样做,您可能会发现您的应用程序泄漏未经处理的资源,例如句柄或甚至是非托管内存,特别是如果在所有这些下面的某个地方使用了一些 COM 组件,或者调用 Win32 API。这显然会导致性能和稳定性问题,以及资源使用过度。
仅仅因为实现 IDisposable 接口的对象“应该”实现一个终结器,来调用其 Dispose(bool disposing) 方法释放非托管资源,并不能保证这将会发生,所以您绝对不能依赖它。有关此问题的更多信息,请参见 http://msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspx
此外,还要注意的是,如果您的类型具有可处理的成员,则该类型应实现 IDisposable 接口(除非这些成员的生命周期由另一个类型管理,这显然可能变得混乱),或者,如果您仅在一个方法中使用此类成员,或者为了实现一个特定的功能,则应该考虑将其作为局部变量/参数放在使用它们的方法中。

1

Dispose模式并不保证哪些对象会调用其他对象的Dispose方法;有时可能会发生,但您不应该关心。相反,您有责任确保为所有IDisposable对象调用Dispose()方法。最好的方法是使用using语句。例如:

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

0
我对“在finally块中,手动处理的对象是那些在类级别上设置的对象”这个说法感到困惑。通过“在类级别上设置的对象”,您是否指的是字段?您可能不应该在普通方法中处理这些字段,因为这样字段的生命周期是不可预测的,并且取决于您调用了哪些方法。最好实现IDisposable并在Dispose方法中处理字段。

-2

使用 Using 语句可能有帮助吗?


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