Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么Finalize/Destructor示例在.NETCore中不起作用?_C#_.net_.net Core_Destructor - Fatal编程技术网

C# 为什么Finalize/Destructor示例在.NETCore中不起作用?

C# 为什么Finalize/Destructor示例在.NETCore中不起作用?,c#,.net,.net-core,destructor,C#,.net,.net Core,Destructor,我试图学习C#中的终结和析构函数是如何工作的,我试图运行示例中的代码(粘贴代码副本,不做任何更改),但输出与预期不一样,这表明析构函数从未被调用 代码是: using System; using System.Diagnostics; public class ExampleClass { Stopwatch sw; public ExampleClass() { sw = Stopwatch.StartNew(); Console.WriteLin

我试图学习C#中的终结和析构函数是如何工作的,我试图运行示例中的代码(粘贴代码副本,不做任何更改),但输出与预期不一样,这表明析构函数从未被调用

代码是:

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 该示例显示如下输出: 实例化对象 ExampleClass的此实例已存在00:00:00.0011060 终结对象 ExampleClass的此实例已存在00:00:00.0036294 当我使用dotnet core应用程序时,代码不起作用: 实际输出为:

PS C:\ws\test> dotnet run Instantiated object This instance of ExampleClass has been in existence for 00:00:00.0056874 PS C:\ws\test>dotnet运行 实例化对象 ExampleClass的此实例已存在00:00:00.0056874
那么这在.NET Core中有什么不同呢?

在垃圾回收器运行之前不会发生终结。除非需要(例如,内存不足)或需要,否则不会运行垃圾收集

尝试添加

System.GC.Collect();

查看终结器是否在这种情况下运行。

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

这种行为违反了Microsoft和的C#5.0规范,其中规定:

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

但这不是一个bug,.Net Core故意偏离.Net Framework行为,如中所述:

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

提议 关闭时不运行终结器(对于可访问或不可访问的对象)

根据该提案,不能保证所有可终结对象在关闭前都能终结

大概是由于这个原因,削弱了这个要求,所以.Net Core没有违反这个版本的规范:

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


添加
GC.Collect
没有任何区别。但除此之外,我的困惑是MSDN示例不使用GC.Collect,但它显示终结器按预期调用。GC应该在程序退出之前运行。根据C#规范:“在应用程序终止之前,调用其所有尚未被垃圾收集的对象的析构函数”。问题似乎很清楚,是“为什么.NET Core不符合规范?”,而不是“我如何解决这个问题?”添加
GC.Collect()
确实会有所不同,但只是在发布模式下。这是因为在调试模式下,局部变量仍在作用域中时不会被收集。虽然这并不能真正回答问题。“这是一个语言特性,对吗?”——没有语言特性可以保证调用终结器。这就是为什么任何代码都不应该假设会调用一个。终结器严格地说是作为备份,以减轻错误代码造成的伤害。作为记录,使用您的代码示例,我重现了您描述的问题,不,我不知道.NET Core在正常程序退出时无法终结对象的原因。听起来像个虫子。规范似乎相当清晰,因此除非.NET Core中有某种东西,通过设计,在正常程序终止之前,“抑制”对象的终结,.NET Core违反了规范。我认为这是一个@fluer-您提到的规范是关于C语言的。在我看来,这似乎超越了它的界限,这是关于平台的行为,而不是语言。但我认为这还不够,所以我创建了。他们禁用了终结器线程超时。加克。好吧,从那以后,除了“不要做所有的事”之外,别无选择。弱酱汁。“ECMA当前的C#5.0规范草案”——切题,但是:什么?我查看了链接,看起来确实是C#5的规范(规范中没有C#6特性)。ECMA似乎落后于C版本。“.Net核心不违反此版本的规范”--我不确定我是否同意。这些变化表明了行为可能有所不同的原因,但没有证据表明.NETCore“尽了一切合理的努力”,也没有证据表明该行为已被记录在案。也许他们正朝着这个方向前进,但似乎还没有到达那里(@PeterDuniho是的,ECMA有很多工作要做。但是C#任务组由Jon Skeet领导,所以我相信不会花那么长时间。我同意ECMA草案的措辞与.Net核心行为不完全一致,这就是我创建的原因。你可以补充一点,这现在已经有了完整的文档:“in.Net Framework应用程序(但不是在.NET核心应用程序中),程序退出时也会调用终结器。”