为什么Finalize / Destructor示例在.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时,代码按预期工作:输出与示例相同:

 该示例显示如下输出:
   实例化对象
    ExampleClass的这个实例已经存在于00:00:00.0011060
   完成对象
    ExampleClass的这个实例已经存在于00:00:00.0036294 

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

  PS C:\ ws \ test> dotnet运行
    实例化对象
     ExampleClass的这个实例已经存在于00:00:00.0056874 

那么为什么.NET Core会有所不同呢?

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

此行为违反了Microsoft的C#5.0规范以及Microsoft 当前的C#6.0规范草案 ,其中说:

在应用程序终止之前,将调用其尚未被垃圾回收的所有对象的析构函数,除非已禁止此类清理(例如,通过调用库方法GC.SuppressFinalize )。

但它不是一个bug,.Net Core故意偏离.Net Framework行为,如corefx问题所述 :

目前,尽最大努力尝试在关闭期间为所有可终结对象运行终结器,包括可到达对象。 为可到达对象运行终结器是不可靠的,因为对象处于未定义状态。

提案

不要在关机时运行终结器(对于可到达或无法到达的对象)

根据此提议,无法保证在关闭之前完成所有可终结对象。

据推测,由于这一点, ECMA的C#5.0规范削弱了这一要求,因此.Net Core没有违反此版本的规范:

在应用程序终止之前,实现应该尽一切合理的努力为其尚未被垃圾收集的所有对象调用终结器(第15.13节),除非已经抑制了这种清理(通过调用库方法GC.SuppressFinalize , 例如)。 实现应记录无法保证此行为的任何条件。

在垃圾收集器运行之前不会进行终结。 垃圾收集不会运行,除非它需要(例如,你的内存不足),或者强制它运行 。

尝试添加

 System.GC.Collect(); 

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