这是一个相当基本的问题,但我仍然在努力解决它。
当您希望在对象最终被垃圾回收之前允许对象的用户释放底层资源(例如套接字等)时,实现了IDisposable。
当我有一个持有DbConnection(实现IDisposable)的类时,我的类是否也需要实现IDisposable并将调用链接到DbConnection或它拥有的任何其他IDisposable对象?否则,只有在我的类为GarbageCollected时才会释放DbConnections资源,从而删除它对连接的引用,GC将最终确定DbConnection。
答案 0 :(得分:9)
是的,如果你控制一次性物品,你总是实施IDisposable。 始终即可。如果你不这样做,你的代码就不会破坏,但是如果不这样做,它就会破坏使用一次性物品的目的。
GC优化的一般规则是:
如果您正在为自己编写应用程序,这些规则可能会被忽略或忽略,但在向其他人分发代码时,您应该专业并遵守规则。
这里的逻辑是,当你在GC视图之外控制内存时,GC引擎无法正确管理你的内存使用情况。例如,在.NET堆上,您可能只有一个4字节的指针,但在非托管的域中,您可以指向200 MB的内存。 GC引擎在你有几十个之前不会尝试收集它们,因为它只看到几个字节;而在现实世界中,它看起来很像内存泄漏。
因此,规则是,当您使用它时,非托管内存应立即释放(IDisposable链为您执行此操作),而GC引擎会随时释放托管内存。
答案 1 :(得分:6)
是的,如果需要处理它使用的任何对象,那么你的类需要是IDisposable。一个例子是StreamReader。它实现了IDisposable,因此它可以处理其关联的流对象。
答案 2 :(得分:3)
如果我理解你的问题,你就有一个使用DbConnection的类。您希望确保在完成DbConnection或处理类时正确处理DbConnection。有几种方法可以实现这一目标。
如果在方法中使用数据库连接作为局部变量,则可以使用using(){}语句。
using (SqlConnection sqlConnection = new SqlConnection(connStr))
{
...do stuff with connection here
}
using(){}语句自动调用()中声明的对象上的Dispose()。 (它还要求()中声明的对象实现IDisposable以确保它们可以被处置。
如果您正在使用DbConnection作为在对象构造期间初始化的私有变量或其他一些初始化方法,那么您可能希望自己实现IDisposable,然后在Dispose()方法中调用_dbConnection.Dispose()。这样,当您的对象被处置时,数据库连接对象也将被处置。
public class MyDALObj : IDisposable
{
public MyDalObj()
{
... create _dbConn object ...
}
public void Dispose()
{
_dbConn.Dispose();
}
private DbConnection _dbConn;
}
答案 3 :(得分:3)
你应该这样做,因为这是你班级用户确保内部资源得到妥善处理的唯一途径。
但是,用于Dispose()的模式可能与通常编写的模式略有不同,在这种情况下,因为您不必区分非托管资源和托管资源(您的封装资源始终被视为“托管” “资源”。
我写了一篇关于这个特定主题的详细博文 - Encapsulating IDisposable Resources。
答案 4 :(得分:2)
有两种不同的情况:
在第二种情况下,您的对象负责所涉及的资源,因此您的对象必须实现IDisposable,并且在处置时,您应该处置您构造的对象。
你的DbConnection属于第二种情况,所以是的,你的对象应该实现IDisposable,然后处理连接。
在第一种情况下,您需要决定以下三种解决方案:
这是很多文字,所以让我总结一下:
还有第三种情况,听起来并不像你所拥有的那样,但仍然如此。
如果在本地构建,使用和丢弃一个对象,在单个方法中,而不传递它或将其存储在类的字段中,则使用using
语句,就像这样:
using (IDbConnection conn = ....())
{
}
答案 5 :(得分:0)
这当然是最好的做法,尤其是在处理繁重/非托管对象时。
编辑:最佳做法,但不是强制性的。
答案 6 :(得分:0)
由于我们永远不知道GC何时会收集对象,因此我们使用IDisposable接口在垃圾收集对象之前有机会有意释放非托管资源。 如果在收集之前未处置一次性对象,则在退出AppDomain之前可能不会释放其资源。 这几乎是一个不成文的规则,每个引用IDisposable对象的对象都应该是IDisposable本身,并在自己的Dispose方法中调用其IDisposable引用的Dispose方法。
答案 7 :(得分:0)
当然,如果使用C ++ / CLI,您可以删除IDisposable的大量(重新)实现成本,并获得与托管堆上对象的确定性最终化非常接近的东西。这是一种经常(我发现)被忽视的一种语言方面,很多人似乎都只是委托给“只用胶水代码”的箱子。
答案 8 :(得分:0)
使用Dispose提供显式控制时,应使用Finalize方法提供隐式清理。如果程序员无法调用Dispose,则Finalize提供备份以防止资源永久泄漏。
我认为实现这一点的最佳方法是使用Dispose和Finalize方法的组合。 您可以找到更多Here。