。净 IDisposable图案 意味着 如果你写一个终结,并执行IDisposable,你的终结,需要明确地呼吁处置。这是合乎逻辑的,并且是什么我一直在做的,在罕见的情况下终结是必要的。

然而,如果发生了什么我只是做这样的:

class Foo : IDisposable
{
     public void Dispose(){ CloseSomeHandle(); }
}

并且不要实行一个终结,或者任何东西。会框架内调用的处理方法对于我吗?

是的我知道这听起来很蠢,和所有的逻辑意味着它不会,但我一直有2件事情在我的头后面有了我不能确定。

  1. 有人几年前曾经告诉我,它实际上这样做,并且该人有一个非常坚实的跟踪记录"了解自己的东西。"

  2. 编译器/框架其他的"魔法"的事情根据接口实施(例如:foreach,扩展的方法,化基于属性,等等),因此是有意义的,这可能是"魔法"。

同时我读了很多东西,并有很多很多的事情暗示的,我从来没有能够找到一个 最终 是的或者没有回答这个问题。

有帮助吗?

解决方案

。净垃圾收集器的呼吁的对象。最后确定对象的方法上的垃圾收集。通过 默认的 这并 没有什么 必须复盖,如果你想要免费的额外资源。

处理不是自动调,必须 明确 称为如果资源得到释放,诸如在使用'或'尝试终于'块

看看 http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx 更多信息

其他提示

我想强调的是布莱恩的一点在他的评论,因为它是重要的。

终结器不确定性析构想在C++。正如其他人已经指出的那样,没有保证时,它将被称,而事实上如果你有足够的存储器,如果它会 曾经 被称为。

但不好的事情终结器是,作为布莱恩所说,这会导致你的对象生存的一个垃圾收集。这可能是坏的。为什么?

你可能或不可能知道的,总是分成几代人代0、1和2,加大对象堆。分裂是一个松散的词-你会得到一块的存储器,但有的指针的代0对象的开始和结束。

思维过程是,你可能会使用大量的对象将是短暂的。因此,这些应该是容易和快速的GC得到代0对象。所以,当有记忆的压力,第一件事它不是一个艮0收集。

现在,如果不解决足够的压力,然后它返回和不Gen1扫(重新艮0),然后如果仍然不够,这并Gen2扫(重新Gen1和Gen为0)。所以清除长期以来生活的对象可能需要一段时间并且是相当昂贵的(因为你的线可能会被暂停期间的工作)。

这意味着,如果你做事情是这样的:

~MyClass() { }

你的对象,无论怎样,将生活产生2.这是因为GC有没有办法的呼叫终结期间,垃圾收集。因此对象,有待最后确定将迁移到一个特殊的队列为可清理出一个不同的线(最终结线-如果你杀了使所有种不好的事情发生)。这意味着你的对象挂在更长,并可能迫使更多的垃圾回收。

因此,所有这一切只是开车回家,你想使用IDisposable清理资源尽可能认真地试图找到办法绕过使用终结.这是在你的应用程序的最佳利益。

有许多很好的讨论已经在这里了,我有点迟到了,但我想补充几点我自己。

  • 垃圾收集器将永远不会直接执行一个处理方法。
  • GC 执行终结器的时候感觉就像它。
  • 一个常见的模式,用针对的对象有一个终结就是把它叫一种方法,它是由公约定义为处理(bool处置)通过虚假指示,该呼吁是由于最后定稿,而不是一个明确的处置的呼吁。
  • 这是因为它不是安全作出任何假设有关其他管理对象的,同时定稿的对象(他们可能已经最后定稿).

class SomeObject : IDisposable {
 IntPtr _SomeNativeHandle;
 FileStream _SomeFileStream;

 // Something useful here

 ~ SomeObject() {
  Dispose(false);
 }

 public void Dispose() {
  Dispose(true);
 }

 protected virtual void Dispose(bool disposing) {
  if(disposing) {
   GC.SuppressFinalize(this);
   //Because the object was explicitly disposed, there will be no need to 
   //run the finalizer.  Suppressing it reduces pressure on the GC

   //The managed reference to an IDisposable is disposed only if the 
   _SomeFileStream.Dispose();
  }

  //Regardless, clean up the native handle ourselves.  Because it is simple a member
  // of the current instance, the GC can't have done anything to it, 
  // and this is the onlyplace to safely clean up

  if(IntPtr.Zero != _SomeNativeHandle) {
   NativeMethods.CloseHandle(_SomeNativeHandle);
   _SomeNativeHandle = IntPtr.Zero;
  }
 }
}

这就是简单的版本,但存在很多细微差别,可以你绊在这种模式。

  • 合同IDisposable.处理表示,它必须是安全的电话多次(调用处置的对象是已经设置应该做什么)
  • 它可以获得非常复杂的妥善管理的一个继承层次结构的一次性目的,特别是如果不同层引入新的一次性而非管理的资源。在模式上述处置(bool)是虚拟的,使其能够改写,以便它可以管理的,但是我找到它可以容易出错。

在我看来,最好是完全避免具有任何类型的直接包含两个一次性的参考文献和当地资源,可能需要最后定稿。SafeHandles提供一个非常简洁的方式这样做的通过封装当地的资源投入到一次性的,在内部提供它们自己的定稿(随着一些其他好处一样除去窗口期间的P/援引其中一个当地处理可能由于失去了一个异例外)。

简单地定义SafeHandle使得这一微不足道的:


private class SomeSafeHandle
 : SafeHandleZeroOrMinusOneIsInvalid {
 public SomeSafeHandle()
  : base(true)
  { }

 protected override bool ReleaseHandle()
 { return NativeMethods.CloseHandle(handle); }
}

可以让你简化含有类型:


class SomeObject : IDisposable {
 SomeSafeHandle _SomeSafeHandle;
 FileStream _SomeFileStream;
 // Something useful here
 public virtual void Dispose() {
  _SomeSafeHandle.Dispose();
  _SomeFileStream.Dispose();
 }
}

我不这么认为。你必须控制过时的处置是所谓的,这意味着你可以在理论上写的处置码,即使假设(例如)存在其他对象。你有没有控制时是所谓的终结,因此它将是前途未卜有的终结的自动电话处理掉您的代表。


编辑:我去和试验,只是为了确保:

class Program
{
    static void Main(string[] args)
    {
        Fred f = new Fred();
        f = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("Fred's gone, and he's not coming back...");
        Console.ReadLine();
    }
}

class Fred : IDisposable
{
    ~Fred()
    {
        Console.WriteLine("Being finalized");
    }

    void IDisposable.Dispose()
    {
        Console.WriteLine("Being Disposed");
    }
}

不是在你所说的, 但GC会打电话的 终结 你,如果你有一个。

然而。下一个垃圾收集,而不是被收集,目将进入最后定稿阙,一切得到收集,那么它就是所谓的终结.下一个收集之后,它将被释放。

根据存储器中的压力的应用程序,可能没有气相色谱仪的对象产生一段时间。因此,在这种情况下的说,一个流的文件或数据库的连接,可能需要等待一段时间的不受管理的资源被释放的呼叫终结一段时间,造成一些问题。

不,这不叫。

但是这使得易于不要忘记处理你的对象。只是使用 using 关键词。

我做了以下试验:

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo();
        foo = null;
        Console.WriteLine("foo is null");
        GC.Collect();
        Console.WriteLine("GC Called");
        Console.ReadLine();
    }
}

class Foo : IDisposable
{
    public void Dispose()
    {

        Console.WriteLine("Disposed!");
    }

GC会 呼叫处置。它的 叫你的终结,但即使这不能保证在所有情况。

看看这个 文章 讨论最好的方式来处理这个问题。

该文件 IDisposable 给出一个相当明确和详细解释行为,以及例码。GC不会叫的 Dispose() 方法上的接口,但是它将呼叫终结对你的对象。

IDisposable模式创建的,主要是通过所谓的开发,如果你有一个对象实现IDispose开发商应该实现的 using 关键词左右的上下文的对象或呼叫的处置方法。

失败的安全的模式来实施的终结叫Dispose()方法。如果你不做,你可以创建一些存储器泄漏,即:如果你创建的一些COM包装,从不打电话系统。运行时间。互操作。马歇尔。ReleaseComObject(comObject)(这将被放置在处理方法)。

没有魔法的clr叫处置方法自动比其他的跟踪对象包含终结器,并将它们存放在终结表通过的GC并呼吁他们在一些干净了启发式踢通过的GC。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top