首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >既然我们没有析构函数,为什么还要调用SuppressFinalize呢

既然我们没有析构函数,为什么还要调用SuppressFinalize呢
EN

Stack Overflow用户
提问于 2010-04-09 14:14:12
回答 5查看 11.4K关注 0票数 30

我有几个问题得不到正确的答案。

1)当我们没有析构函数时,为什么要在Dispose函数中调用SuppressFinalize?

2) Dispose和finalize用于在对象被垃圾回收之前释放资源。无论它是托管的还是非托管的资源,我们都需要释放它,那么为什么我们需要dispose函数内部的一个条件,当我们从IDisposable调用这个被覆盖的函数时,说pass 'true‘:Dispose,当从finalize调用时,传递false。

请看我从net复制的下面的代码。

代码语言:javascript
复制
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);
     }
   }

如果我删除boolean protected Dispose函数并按如下方式实现会怎么样?

代码语言:javascript
复制
   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);
     }
   }       
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-04-09 14:35:01

我这是在冒险,但是...大多数人不需要成熟的dispose模式。它被设计成在直接访问非托管资源(通常通过IntPtr)和面对继承时是可靠的。大多数情况下,这两者实际上都不是必需的。

如果您只是持有对实现IDisposable的其他东西的引用,那么几乎可以肯定的是,您不需要终结器-直接持有资源的任何东西都负责处理它。你可以用下面这样的东西来凑合:

代码语言:javascript
复制
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标志:如果你在终结器中运行,你引用的其他对象可能已经被终结了。你应该让他们自己清理,而且你应该只清理你直接拥有的资源。

票数 26
EN

Stack Overflow用户

发布于 2010-04-29 19:59:45

以下是主要事实

1)当你的类有一个终结器时,Object.Finalize就是它所覆盖的东西。TypeName()析构函数方法只是'override Finalize()‘等的简写

2)如果在终结化之前在Dispose方法中处理资源(例如,当从using块中出来时),则调用GC.SuppressFinalize。如果您没有终结器,则不需要执行此操作。如果你有一个终结器,这确保了对象从终结化队列中被移除(所以我们不会两次释放东西,因为终结器通常也会调用dispose方法)

3)你实现一个终结器作为一种“故障安全”机制。终结器保证会运行(只要CLR没有中止),所以它们允许你确保代码在Dispose方法没有被调用的情况下得到清理(也许程序员忘记在“using”块中创建实例等等)。

4)终结器是昂贵的,因为具有终结器的类型不能在Generation-0集合中被垃圾收集(最有效),并且通过在F-Reachable队列上引用它们来提升到Generation-1,因此它们表示GC根。直到GC执行第一代收集时,终结器才会被调用,资源才会被释放-所以只有在非常重要的情况下才实现终结器-并确保需要终结器的对象尽可能小-因为可终结化对象可以到达的所有对象也将被提升到第一代。

票数 6
EN

Stack Overflow用户

发布于 2010-04-09 14:24:36

保留第一个版本,它更安全,并且是dispose模式的正确实现。

  1. 调用SuppressFinalize告诉GC您已经完成了(类持有的)所有资源的销毁/处置,并且它不需要调用需要测试的destructor.
  2. You,以防使用您的类的代码已经调用了dispose,并且您不应该告诉GC再次进行dispose。

参见Dispose MSDN文档(Dispose方法应该调用SuppressFinalize)。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2605412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档