C# 实现Finalize和Dispose的正确方法(当父类实现IDisposable时)

C# 实现Finalize和Dispose的正确方法(当父类实现IDisposable时),c#,.net,wpf,idisposable,finalizer,C#,.net,Wpf,Idisposable,Finalizer,我在类中实现Finalize和Dispose,在父类中实现IDisposable,并在子类中重写Dispose(bool)重载。我不确定 是否使用重复的isDisposed变量(因为它已经存在于基类中) 是否也在子类中实现终结器 这两件事都在这里给出的示例中完成- 而本MSDN文章中的示例没有这两个选项中的任何一个- 然而,MSDN中的这个示例并不完整- 1)无需复制 2) 实现终结器将有助于处置未明确处置的项目。但是,不保证。这是一个很好的做法。需要重复 如果在子类中没有任何清理,只需调用

我在类中实现Finalize和Dispose,在父类中实现IDisposable,并在子类中重写Dispose(bool)重载。我不确定

  • 是否使用重复的isDisposed变量(因为它已经存在于基类中)
  • 是否也在子类中实现终结器
  • 这两件事都在这里给出的示例中完成-

    而本MSDN文章中的示例没有这两个选项中的任何一个-

    然而,MSDN中的这个示例并不完整- 1)无需复制

    2) 实现终结器将有助于处置未明确处置的项目。但是,不保证。这是一个很好的做法。

    需要重复

    如果在子类中没有任何清理,只需调用
    base.Dispose()
    ,如果有一些类级清理,则在调用
    base.Dispose()
    后进行清理。您需要分离这两个类的状态,这样每个类都应该有一个
    IsDisposed
    boolean。通过这种方式,您可以随时添加清理代码


    当您确定一个类为
    IDisposable
    时,您只需告诉
    GC
    我正在处理它的清理过程,并且您应该
    SuppressFinilize
    对该类进行处理,以便
    GC
    将其从队列中删除。除非调用
    GC.supersFinalize(this)
    否则
    IDisposable
    类不会发生任何特殊情况。因此,如果您像我提到的那样实现它,就没有必要使用
    Finilizer
    ,因为您刚刚告诉
    GC
    不要完成它。

    实现IDisposable的正确方法取决于您的类是否拥有任何非托管资源。实现IDisposable的确切方法仍然不是所有开发人员都同意的,有些人对一次性范式有强烈的看法

    见:

    的文档也简要地解释了这一点,并指出了一些相同的东西,但也在MSDN上


    至于基类中是否需要重复的布尔字段“isDisposed”。似乎这只是一个有用的约定,当子类本身可能添加需要处置的其他非托管资源时,可以使用它。由于Dispose被声明为虚拟的,因此对子类实例调用Dispose总是导致首先调用该类的Dispose方法,然后调用base.Dispose,因为这是最后一步,它提供了清除继承层次结构中每个级别的机会。因此,我可能会将其总结为,如果您的子类在基本类所拥有的资源之上有额外的非托管资源,那么您可能最好在其Dispose方法中拥有自己的boolean isDisposed字段,以事务性质跟踪其处置,但正如Ian在回答中提到的,还有其他方法来表示已处理的状态。

    终结器很少有用。您链接到的文档并非完全有用-它提供了以下循环建议:

    仅在对象上实现Finalize 这需要最后定稿

    这是一个很好的乞求问题的例子,但它不是很有帮助

    实际上,绝大多数情况下,您不需要终结器。(.NET开发人员必须经历的一个学习过程是发现,在大多数他们认为需要终结器的地方,他们不需要终结器。)您已经将此标记为(除其他外)WPF问题,我要说的是,在UI对象上放置终结器几乎总是一个错误。(因此,即使您处于需要终结器的异常情况下,该工作也不属于与WPF相关的任何代码。)

    在大多数情况下,终结器似乎很有用,但事实证明并非如此,因为当终结器运行时,它已经太晚了,无法做任何有用的事情

    例如,尝试对对象引用的任何对象执行任何操作通常都不是一个好主意,因为在终结器运行时,这些对象可能已经终结。(.NET不保证终结器的运行顺序,因此您根本无法知道是否有要终结的引用的对象。)在终结器已经运行的对象上调用方法是个坏主意

    如果你有办法知道某个对象肯定还没有完成,那么使用它是安全的,但这是一个非常不寻常的情况。(…除非所讨论的对象没有终结器,并且本身也没有使用可终结的资源。但在这种情况下,当您自己的对象消失时,您可能不需要对其执行任何操作。)

    终结器看起来很有用的主要情况是互操作:例如,假设您使用p/Invoke调用某个非托管API,并且该API返回一个句柄。也许您需要调用其他API来关闭该句柄。由于这些都是非托管的东西,.NET GC不知道这些句柄是什么,您的工作是确保它们得到清理,在这一点上终结器是合理的……除了在实践中,对于这种情况,几乎总是最好使用
    安全句柄

    在实践中,我发现自己使用终结器的唯一地方是a)设计用于调查GC的功能的实验,以及b)设计用于发现系统中如何使用特定对象的诊断代码。这两种代码都不应该最终投入生产

    所以,对于是否需要“在子类中也实现终结器”的答案是:如果需要,那么答案是否定的

    至于是否要复制国旗……其他答案则相反