代码之家  ›  专栏  ›  技术社区  ›  SwDevMan81 Chris Barlow

何时不调用Dispose方法?

  •  6
  • SwDevMan81 Chris Barlow  · 技术社区  · 15 年前

    我在读书 this 前几天,我在想为什么会有一个终结器和Dispose方法。我读 here 关于您可能希望向终结器添加Dispose的原因。奇怪的是,什么时候才能对Dispose方法本身调用终结器?是否有代码示例,或者它是基于运行软件的系统上发生的事情?如果是这样,那么发生的事情可能是GC没有运行Dispose方法。

    5 回复  |  直到 13 年前
        1
  •  9
  •   Noldorin    15 年前

    决赛选手的目的只是为了防止记忆泄漏(如果发生 打电话 Dispose 明确地)。它还意味着,如果您希望在程序关闭时释放资源,就不必处理对象,因为GC无论如何都将被迫完成并收集所有对象。

    作为一个相关的观点,重要的是,在与决赛选手相比,处理物体时要稍微有所不同。

    ~MyClass()
    {
        Dispose(false);
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected void Dispose(disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }
            // Dispose unmanaged resources here.
        }
        this.disposed = true;
    }
    

    你的原因 想要在决赛选手中处置管理的资源,实际上是在这样做的过程中创建了对它们的有力引用,这可能会阻止GC正确地执行它的工作并收集它们。当然,非托管资源(如win32句柄等)应该总是显式关闭/释放,因为clr不知道这些资源。

        2
  •  4
  •   Reed Copsey    15 年前

    这主要是为了保护你自己。您不能指定类的最终用户将做什么。通过提供除Dispose方法之外的终结器,GC将“释放”您的对象,适当地释放您的资源,即使用户忘记调用Dispose()或错误地使用您的类。

        3
  •  2
  •   Mike Minutillo    15 年前

    当对象被垃圾收集时,将调用终结器。需要显式调用Dispose。在以下代码中,将调用终结器,但Dispose方法不是。

    class Foo : IDisposable
    {
      public void Dispose()
      {
        Console.WriteLine("Disposed");
      }
    
      ~Foo()
      {
        Console.WriteLine("Finalized");
      }
    }
    
    ...
    
    public void Go()
    {
      Foo foo = new Foo();
    }
    
        4
  •  1
  •   kemiller2002    15 年前

    必须通过调用Dispose()或在using语句中包含对象来显式调用Dispose方法。GC总是调用终结器,因此如果在处理对象之前需要发生一些事情,终结器至少应该检查以确保对象中的所有内容都已清理干净。

    您希望尽可能避免清理终结器中的对象,因为与在手前处理对象相比,它会导致额外的工作(如调用Dispose),但如果周围有需要删除的对象,则应始终至少签入终结器。

        5
  •  0
  •   supercat    13 年前

    一个重要但微妙的注意事项尚未提及:很少考虑的处理目的是防止对象过早被清理。必须仔细编写带有终结器的对象,以免运行终结器 早期的 超出预期。终结器不能在将对对象(*)进行的最后一个方法调用开始之前运行,但它有时可能会运行 在期间 如果对象在方法完成后将被放弃,则调用最后一个方法。正确处理对象的代码不能在调用Dispose之前放弃对象,因此终结器不会对正确使用Dispose的代码造成破坏。另一方面,如果最后一个使用对象的方法使用了在最后一次使用对象引用本身之后将在终结器中清除的实体,则垃圾收集器可以对该对象调用Finalize并清除仍在使用的实体。补救方法是确保任何使用要由终结器清除的实体的调用方法在某个时刻都必须后跟使用“this”的方法调用。keepalive(这)是一个很好的方法。

    (*)将非虚拟方法扩展为对对象不做任何操作的内嵌代码,可以免除此规则,但Dispose通常是或调用虚拟方法。