我对如何使用Dispose()
和析构函数有疑问。阅读一些文章和MSDN documentation,这似乎是实现Dispose()
和析构函数的推荐方法。
但是我对这个实现有两个问题,你可以在下面阅读:
class Testing : IDisposable
{
bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_disposed) // only dispose once!
{
if (disposing)
{
// Not in destructor, OK to reference other objects
}
// perform cleanup for this object
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
// tell the GC not to finalize
GC.SuppressFinalize(this);
}
~Testing()
{
Dispose(false);
}
}
在Dispose()上当程序员使用using
或调用Dispose()显式时,我们的类正在调用GC.SupressFinalize(this)
。我的问题是:
假设GC要清理我们的对象,但程序员没有调用Dispose()
必须在if里面执行什么代码,在外面执行什么?
if (!_disposed) // only dispose once!
{
if (disposing)
{
//What should I do here and why?
}
// And what here and why?
}
提前致谢
答案 0 :(得分:13)
它从终结器列表中取消注册对象,即当GC稍后收集对象时,它将忽略析构函数的存在。这是性能上的一大进步,因为析构函数否则需要对象的集合以及它所引用的所有内容的延迟。
你可以,但肯定是没有意义的:你所在的对象已无法访问,因此所有拥有的托管资源也无法访问。它们将在同一次运行中由GC完成并收集,并且调用它们上的Dispose()是不必要的,但并非完全没有风险或成本。
2a必须在if里面执行什么代码,在外面执行什么?
在if(disposing)
内,请致电_myField.Dispose()
换句话说,处理托管资源(具有Dispose的对象)
在外面,调用代码来清理(关闭)非托管资源,例如Win32API.Close(_myHandle)
。
请注意,当您没有非托管资源时(通常是这样)(查找SafeHandle),您不需要析构函数,因此不需要SuppressFinalize。
这使得仅需要完整(官方)实现此模式,因为Test可能继承自。
请注意Dispose(bool)
受到保护。当您将类测试声明为sealed
时,它是完全安全的并且符合省略~Testing()
。
答案 1 :(得分:2)
第一部分:
当调用GC.SupressFinalize(this)
时,GC会被告知该对象已经释放了其资源,并且可以将其作为任何其他对象进行垃圾收集。是的,终结和“析构函数”在.NET中是相同的。
第二部分:
最终确定由一个单独的线程完成,我们无法控制最终确定的时间和顺序,因此我们不知道是否有任何其他对象仍然可用或已经完成。因此,您无法引用disposing
块之外的其他对象。
答案 2 :(得分:1)
绝大多数情况下,拥有IDisposable
资源的对象最终确定后,以下至少一项陈述将适用于这些资源:
在上述情况都不适用的一些罕见情况下,终结者内的清理可能是合适的,但除非人们首先检查上述四种可能性,否则不应该考虑清除。