2024-09-20 10:00:04

Finalize vs Dispose

为什么有些人使用Finalize方法而不是Dispose方法?

在什么情况下你会使用Finalize方法而不是Dispose方法,反之亦然?


当前回答

完成

Finalizers should always be protected, not public or private so that the method cannot be called from the application's code directly and at the same time, it can make a call to the base.Finalize method Finalizers should release unmanaged resources only. The framework does not guarantee that a finalizer will execute at all on any given instance. Never allocate memory in finalizers or call virtual methods from finalizers. Avoid synchronization and raising unhandled exceptions in the finalizers. The execution order of finalizers is non-deterministic—in other words, you can't rely on another object still being available within your finalizer. Do not define finalizers on value types. Don't create empty destructors. In other words, you should never explicitly define a destructor unless your class needs to clean up unmanaged resources and if you do define one, it should do some work. If, later, you no longer need to clean up unmanaged resources in the destructor, remove it altogether.

拥有

Implement IDisposable on every type that has a finalizer Ensure that an object is made unusable after making a call to the Dispose method. In other words, avoid using an object after the Dispose method has been called on it. Call Dispose on all IDisposable types once you are done with them Allow Dispose to be called multiple times without raising errors. Suppress later calls to the finalizer from within the Dispose method using the GC.SuppressFinalize method Avoid creating disposable value types Avoid throwing exceptions from within Dispose methods

处理/确定模式

Microsoft recommends that you implement both Dispose and Finalize when working with unmanaged resources. The Finalize implementation would run and the resources would still be released when the object is garbage collected even if a developer neglected to call the Dispose method explicitly. Cleanup the unmanaged resources in the Finalize method as well as Dispose method. Additionally call the Dispose method for any .NET objects that you have as components inside that class(having unmanaged resources as their member) from the Dispose method.

其他回答

我今天一直在寻找这个问题的答案。我将在这里分享我的经验。我的答案是基于这个联系,因为它有我所见过的最清楚的解释。

当您的对象访问非托管资源时,您必须手动释放这些资源。这可以通过IDisposable或finalizer来完成,这意味着它们都会释放非托管资源。

经验法则: 实现IDisposable以释放非托管资源,调用方代码必须调用Dispose方法。如果调用者忘记调用Dispose()方法,您仍然可以提供一个方法来释放那些非托管资源。第一个选择是使用安全句柄来包装非托管资源。第二个选项是定义终结器。在这种情况下,建议使用安全手柄。

我认为这种联系是对这个问题最明确的答案。我不知道为什么人们在网上对这个问题给出复杂的解释。这让我很困惑,直到我找到了那个联系。

Dispose和Finalize之间的主要区别是:

Dispose通常由代码调用。当您调用它时,资源立即被释放。人们忘记调用这个方法,所以使用(){}语句被发明出来。当您的程序完成{}内代码的执行时,它将自动调用Dispose方法。

您的代码不会调用Finalize。它意味着由垃圾收集器(GC)调用。这意味着在将来的任何时候,只要GC决定这样做,就可以释放资源。当GC工作时,它将通过许多Finalize方法。如果你在这里面有沉重的逻辑,它会使过程变慢。这可能会导致程序的性能问题。所以小心你放进去的东西。

我个人会在Dispose中编写大部分销毁逻辑。希望这能消除困惑。

要回答第一部分,你应该提供人们使用的例子 完全相同的类对象的不同方法。 否则就很难(甚至很奇怪)回答。

至于第二个问题,最好先读这个 正确使用IDisposable接口 它声称

这是你的选择!但是选择“处理”。

换句话说:GC只知道终结器(如果有的话)。也称为微软的析构函数)。 好的代码会同时尝试从(终结器和Dispose)进行清理。

摘要如下-

You write a finalizer for your class if it has reference to unmanaged resources and you want to make sure that those unmanaged resources are released when an instance of that class is garbage collected automatically. Note that you can't call the Finalizer of an object explicitly - it's called automatically by the garbage collector as and when it deems necessary. On the other hand, you implement the IDisposable interface(and consequently define the Dispose() method as a result for your class) when your class has reference to unmanaged resources, but you don't want to wait for the garbage collector to kick in (which can be anytime - not in control of the programmer) and want to release those resources as soon as you are done. Thus, you can explicitly release unmanaged resources by calling an object's Dispose() method.

另外,另一个区别是——在Dispose()实现中,您也应该释放托管资源,而在Finalizer中不应该这样做。这是因为对象引用的托管资源很可能在准备完成之前就已经被清理了。

对于使用非托管资源的类,最佳实践是同时定义Dispose()方法和Finalizer,以便在开发人员忘记显式地释放对象时作为备用方案使用。两者都可以使用共享的方法来清理托管和非托管资源:-

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

Class instances often encapsulate control over resources that are not managed by the runtime, such as window handles (HWND), database connections, and so on. Therefore, you should provide both an explicit and an implicit way to free those resources. Provide implicit control by implementing the protected Finalize Method on an object (destructor syntax in C# and the Managed Extensions for C++). The garbage collector calls this method at some point after there are no longer any valid references to the object. In some cases, you might want to provide programmers using an object with the ability to explicitly release these external resources before the garbage collector frees the object. If an external resource is scarce or expensive, better performance can be achieved if the programmer explicitly releases resources when they are no longer being used. To provide explicit control, implement the Dispose method provided by the IDisposable Interface. The consumer of the object should call this method when it is done using the object. Dispose can be called even if other references to the object are alive.

注意,即使通过Dispose方法提供显式控制,也应该使用Finalize方法提供隐式清理。Finalize提供了一个备份,以防止程序员在调用Dispose失败时永久地泄漏资源。