为什么 Finalize/Destructor 示例在 .NET Core 中不起作用?

Why does the Finalize/Destructor example not work in .NET Core?

我正在尝试学习 C# 中的终结和析构函数是如何工作的,我尝试 运行 System.Object.Finalize 示例中的代码(代码复制粘贴,未进行任何更改),但是输出与预期不一样,表明从未调用过析构函数。

密码是:

using System;
using System.Diagnostics;

public class ExampleClass
{
   Stopwatch sw;

   public ExampleClass()
   {
      sw = Stopwatch.StartNew();
      Console.WriteLine("Instantiated object");
   } 

   public void ShowDuration()
   {
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                    this, sw.Elapsed);
   }

   ~ExampleClass()
   {
      Console.WriteLine("Finalizing object");
      sw.Stop();
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                    this, sw.Elapsed);
   }
}

public class Demo
{
   public static void Main()
   {
      ExampleClass ex = new ExampleClass();
      ex.ShowDuration();
   }
}

更新:

当我使用 visual studio 和 .net framework 4.5 时,代码按预期工作: 输出与示例相同:

The example displays output like the following:
   Instantiated object
   This instance of ExampleClass has been in existence for 00:00:00.0011060
   Finalizing object
   This instance of ExampleClass has been in existence for 00:00:00.0036294

当我使用 dotnet 核心应用程序时,代码不起作用: 实际输出为:

PS C:\ws\test> dotnet run
    Instantiated object
    This instance of ExampleClass has been in existence for 00:00:00.0056874

那么为什么这在 .NET Core 中有所不同?

直到垃圾收集器 运行s 才会完成。垃圾收集不会 运行 除非它需要(例如你的内存不足),或者如果你 force it to run.

尝试添加

System.GC.Collect();

添加到您的代码中,看看终结器 运行 是否在那种情况下。

将 Peter Duniho 和 Henk Holterman 的评论中的信息汇总并进一步扩展:

此行为违反了 Microsoft 的 C# 5.0 规范和 current draft of the C# 6.0 spec from Microsoft,其中规定:

Prior to an application's termination, destructors for all of its objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example).

但这不是错误,.Net Core 有意偏离 .Net Framework 行为,如 a corefx issue:

中所述

Currently, a best-effort attempt is made to run finalizers for all finalizable objects during shutdown, including reachable objects. Running finalizers for reachable objects is not reliable, as the objects are in an undefined state.

Proposal

Don't run finalizers on shutdown (for reachable or unreachable objects)

Under this proposal, it is not guaranteed that all finalizable objects will be finalized before shutdown.

大概是因为这个原因,the C# 5.0 spec from ECMA削弱了这个要求,所以.Net Core没有违反这个版本的规范:

Prior to an application’s termination, an implementation should make every reasonable effort to call finalizers (§15.13) for all of its objects that have not yet been garbage collected, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example). The implementation should document any conditions under which this behavior cannot be guaranteed.