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

flu*_*ter 13 .net c# 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();
   }
}
Run Code Online (Sandbox Code Playgroud)

更新:

当我使用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会有所不同呢?

svi*_*ick 15

将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) ).实现应记录无法保证此行为的任何条件.