我的问题很少,我无法得到正确答案。
1)当我们没有析构函数时,为什么要在Dispose函数中调用SuppressFinalize。
2)Dispose和finalize用于在对象被垃圾回收之前释放资源。无论是托管资源还是非托管资源我们都需要释放它,那么为什么我们需要在dispose函数中使用一个条件,当我们从IDisposable调用这个重写函数时传递'true':从finalize调用时Dispose并传递false。
请参阅我从网上复制的以下代码。
class Test : IDisposable
{
private bool isDisposed = false;
~Test()
{
Dispose(false);
}
protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class
isDisposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
如果我删除了布尔保护的Dispose函数并实现如下所示。
class Test : IDisposable
{
private bool isDisposed = false;
~Test()
{
Dispose();
}
public void Dispose()
{
// Code to dispose the managed resources of the class
// Code to dispose the un-managed resources of the class
isDisposed = true;
// Call this since we have a destructor . what if , if we don't have one
GC.SuppressFinalize(this);
}
}
答案 0 :(得分:22)
我在这里走出困境,但......大多数人不需要完整的处置模式。它可以直接访问非托管资源(通常通过IntPtr
)并面向继承。大多数情况下,这些都不是必需的。
如果您只是持有对实现IDisposable
的其他内容的引用,那么您几乎肯定不需要终结器 - 无论什么资源直接保存资源都负责处理。你可以做这样的事情:
public sealed class Foo : IDisposable
{
private bool disposed;
private FileStream stream;
// Other code
public void Dispose()
{
if (disposed)
{
return;
}
stream.Dispose();
disposed = true;
}
}
请注意,此不是线程安全的,但这可能不是问题。
通过不必担心子类直接保存资源的可能性,您不需要抑制终结器(因为没有终结器) - 并且您不需要提供自定义处理的子类方法无论是。没有继承,生活就会变得简单。
如果你做需要允许不受控制的继承(即你不愿意打赌子类会有非常特殊的需求)那么你需要寻找完整的模式。
请注意,使用.NET 2.0中的SafeHandle
,您需要自己的终结器,而不是.NET 1.1中的终结器。
要解决为什么首先出现disposing
标志的问题:如果您在终结器中运行,则您引用的其他对象可能已经完成。你应该让他们自己清理,你应该只清理直接拥有的资源。
答案 1 :(得分:5)
保留第一个版本,它更安全,是配置模式的正确实现。
调用SuppressFinalize
告诉GC你已经完成了所有的破坏/处理(你的类所拥有的资源)并且它不需要调用析构函数。
如果使用您的类的代码已经调用dispose,您需要进行测试,并且不应该告诉GC再次处置。
请参阅this MSDN文档(Dispose方法应调用SuppressFinalize)。
答案 2 :(得分:3)
以下是主要事实
1)Object.Finalize是你的类在具有Finalizer时重写的内容。 ~TypeName()析构函数方法只是'覆盖Finalize()'等的简写
2)如果在最终化之前处理Dispose方法中的资源(即从使用块等出来时),则调用GC.SuppressFinalize。如果您没有Finalizer,那么您不需要这样做。如果你有一个Finalizer,这可以确保该对象从Finalization队列中取出(因此我们不会处理两次,因为Finalizer通常也会调用Dispose方法)
3)您将Finalizer实现为“故障安全”机制。确保终结器运行(只要CLR没有中止),因此它们允许您确保在未调用Dispose方法的情况下清除代码(可能程序员忘记在'using'中创建实例阻止等。
4)终结器很昂贵,因为具有终结器的类型不能在Generation-0集合中进行垃圾收集(效率最高),并且在F-Reachable队列中引用它们被提升为Generation-1,因此它们代表GC根。直到GC执行Generation-1集合才能调用终结器,并释放资源 - 所以只有在非常重要时才实现终结器 - 并确保需要Finalization的对象尽可能小 - 因为所有对象都可以你的终结对象将被提升到第一代。
答案 3 :(得分:3)
<强> 1。回答第一个问题
基本上,如果您的类没有finalize方法(Destructor),则不必调用SuppressFinalize方法。我相信人们甚至在没有确定方法的情况下也会调用SupressFinalize。
<强> 2。回答第二个问题
Finalize方法的目的是释放未受管理的资源。最重要的是要理解,当对象在终结队列中时,会调用Finalize方法。垃圾收集器收集可以销毁的所有对象。垃圾收集器在销毁之前将已完成化的对象添加到终结队列。还有另一个.net后台进程为最终化队列中的对象调用finalize方法。到后台进程执行finalize方法时,该特定对象的其他托管引用可能已被销毁。因为在完成执行时没有特定的顺序。因此,Dispose Pattern希望确保finalize方法不会尝试访问托管对象。这就是为什么托管对象进入“if(disposing)”子句,这对于finalize方法是无法访问的。
答案 4 :(得分:1)
你应该总是调用SuppressFinalize(),因为你可能拥有(或将来有)实现Finalizer的派生类 - 在这种情况下你需要它。
假设您有一个没有Finalizer的基类 - 并且您决定不调用SuppressFinalize()。然后3个月后,您添加一个添加Finalizer的派生类。您可能会忘记进入基类并添加对SuppressFinalize()的调用。如果没有终结器,调用它是没有害处的。
我建议的IDisposable模式发布在这里:How to properly implement the Dispose Pattern