我有一个类(myClass),它有一个从IDisposable派生的类成员(myDisposableMem),因此有一个Dispose()方法。如果它是一个局部变量,我可以使用(...){...}来确保在这个对象上调用Dispose()。但它是一个班级成员。什么是确保在会员上调用Disposed的正确方法?我可以想到两种方式:
1)在类中添加一个finallize(),然后在里面调用myDisposableMem.Dispose()
或
2)让我的类继承自IDisposible:
public class myClass : IDisposable
{
...
public void Dispose()
{
myDisposableMem.Dispose();
}
}
void main ()
{
using (myClass myObj = new MyClass())
{
....
}
}
或许有更好的方法?
答案 0 :(得分:2)
如果一个对象或一段代码拥有引用,则称其为“拥有”IDisposable
,并且没有理由相信任何其他对象或代码段将调用Dispose
它。在放弃该变量之前,拥有本地变量中的IDisposable
的代码通常必须在其上调用Dispose
,或者将其移交给期望获得所有权的其他代码或对象。拥有存储在字段中的IDisposable
的对象通常必须自己实现IDisposable
;其Dispose
方法应检查该字段是否为空,如果不是,则在其上调用Dispose
。
请注意,仅保留对IDisposable
的引用并不意味着应该在其上调用Dispose
。如果一个人有合理的期望没有其他代码可以这样做,那么只应该在Dispose
一个句号上调用IDisposable
。
对象应该覆盖Finalize
,只有它们可以以在未知线程上下文中既有用又安全的方式执行某些清理。通常,对象不应在Dispose
方法中的其他IDisposable
对象上调用Finalize
,因为尽管(与某些来源声称的相反)这些对象保证存在,但其中一个以下条件最有可能适用:
简而言之,如果一个拥有IDisposable
,一般应该认为如果它可以在终结器线程上下文中安全地清理,它将自行处理,如果不能,则不应该试着强迫它。
答案 1 :(得分:0)
您发布的代码用于不同目的
public class myClass : IDisposable
{
...
public void Dispose()
{
myDisposableMem.Dispose();
}
}
暗示当某人(你自己或其他人)调用你的类的Dispose方法时,它也会调用myDisposableMem
上的dispose方法,这是正确的做法(我强烈建议你,如果有其他的话) myClass
上的一次性成员也将其包括在内......)
另一方面
void main ()
{
using (myClass myObj = new MyClass())
{
....
}
}
意味着myObj
不是该类的成员,并且它只能在using语句中使用并稍后处理。
这是两种不同的方案,您必须确定哪种方案适用于您。如果你已经有了该课程的成员,我强烈建议你在myClass
本身处理之前不要处置它,除非你绝对确定没有其他人会使用它并且需要相当多的资源才能离开它在那里。
您对实际代码/场景的更多了解可能有助于我们告诉您应该使用哪种方法。
另请考虑Finalize实际如何运作,this other SO question可能对您有所帮助。
在我看来,我无法保证我就在这里,Dispose()方法确保实现对象在应用程序无法访问之前释放其使用的所有资源,但这并不会将其从堆栈中删除,同时在实现时,在垃圾收集期间调用finalize方法。
答案 2 :(得分:0)
完成并实施IDisposable
不是两个单独的选项;他们应该永远在一起。您应始终实施IDisposable
并清理Dispose()
中的资源,以便用户可以确保及时清理非托管资源。而Dispose()
方法应始终通过调用GC.SuppressFinalize(this)来确保其终结器不会被调用,原因将在稍后解释。
在实施 Nope。请参阅下面的Ilian Pinzon的评论,我显然有一些文档可以尝试再次阅读。 ~MyObject()
时,您应始终实施IDisposable
。它的目的是为垃圾收集器提供一种方法,以确保您的对象始终被丢弃,以防使用它的人无法自行处理。如果你的终结者做的不仅仅是调用this.Dispose()
,那么你可能错误地使用了它。
这真的只是一个安全网。理想情况下,终结器实际上永远不会被调用,因为对象总是被明确地处理掉。当垃圾收集器调用它时,它被迫跳过收集该对象。这反过来意味着它被传递到第二个垃圾收集器生成。这反过来意味着对象将在内存中停留更长时间,最终清理起来会更加昂贵。
尽管如此,最好的选择是将这些一次性对象从类上下文中取出,并尽可能使它们成为方法变量。
例如,如果您有一个连接到数据库的类,请不要将SqlConnection
的主实例存储为字段。相反,让您的公共方法创建自己的连接,并根据需要将它们传递给私有方法。这有两个好处:首先,这意味着您可以在SqlConnections
块中声明using
并完成它。其次,摆脱那种“全球”状态将有助于线程安全,如果你需要它。 (还有一些特定于`SqlConnection的优点,但那些是一般优点。)