.NET Core:最后一块没有在Linux上调用未处理的异常

nla*_*ker 13 c# linux .net-core

我创建了以下C#程序:

namespace dispose_test
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var disp = new MyDisposable())
            {
                throw new Exception("Boom");
            }
        }
    }

    public class MyDisposable : IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我使用它时dotnet run,我看到以下行为:

  • Windows:写入控制台的异常文本,"Disposed"打印~20秒后,程序退出.
  • Linux:写入控制台的异常文本,程序立即退出."处置"从未写过.

Windows上的延迟很烦人,但是在Linux上根本没有调用Dispose()的事实令人不安.这是预期的行为吗?

编辑以下对话中的澄清/补充:

  • 这不是特定的using/Dispose(),这只是一个特例try/finally.行为也通常发生try/finally- finally块未运行.我更新了标题以反映这一点.
  • 我还检查了Dispose()通过将文件写入文件系统来执行,只是为了确保问题与stdout Dispose()在未处理的异常情况下运行之前与控制台断开连接无关.行为是一样的.
  • Dispose()如果在应用程序中的任何位置捕获到异常,则会调用它.当应用程序完全未处理时会发生此行为.
  • 在Windows上,长差距不是由于编译延迟.当异常文本写入控制台时,我开始计时.
  • 我最初的实验是dotnet run在两个平台上进行的,这意味着单独的编译,但我也试过dotnet publish在Windows上直接运行两个平台上的输出,结果相同.唯一的区别是,当直接在Linux上运行时,在异常文本之后写入"Aborted(core dumped)"文本.

版本细节:

  • dotnet --version - > 1.0.4.
  • 编译为netcoreapp1.1,在.NET Core 1.1上运行.
  • lsb-release -d - > Ubuntu 16.04.1 LTS

nla*_*ker 5

官方的回应是,这是一种预期的行为。

有趣的是,最后的C#文档页面在顶部明确地明确指出了这一点(强调我的意思)

在处理的异常内,可以保证关联的finally块可以运行。但是,如果未处理异常,则finally块的执行取决于如何触发异常展开函数。反过来,这取决于计算机的设置方式。有关更多信息,请参见CLR中的未处理异常处理。

通常,当未处理的异常结束应用程序时,是否运行finally块并不重要。但是,如果在即使在那种情况下都必须运行的finally块中有语句,一种解决方案是在try-finally语句中添加catch块。或者,您可以捕获可能在调用堆栈上方的try-finally语句的try块中引发的异常。也就是说,您可以在调用包含try-finally语句的方法的方法中,在调用该方法的方法中或在调用堆栈中的任何方法中捕获异常。如果未捕获到异常,则finally块的执行取决于操作系统是否选择触发异常展开操作。

我在实验中发现的一件事是,它似乎不足以捕获异常,因此您也必须处理它。如果执行catch通过a 离开块throw,则final将不会运行。