C# 实现Finalize和Dispose的正确方法(当父类实现IDisposable时)
我在类中实现Finalize和Dispose,在父类中实现IDisposable,并在子类中重写Dispose(bool)重载。我不确定C# 实现Finalize和Dispose的正确方法(当父类实现IDisposable时),c#,.net,wpf,idisposable,finalizer,C#,.net,Wpf,Idisposable,Finalizer,我在类中实现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)设计用于发现系统中如何使用特定对象的诊断代码。这两种代码都不应该最终投入生产
所以,对于是否需要“在子类中也实现终结器”的答案是:如果需要,那么答案是否定的
至于是否要复制国旗……其他答案则相反