.NET Core:Linux 上未处理的异常未调用 finally 块 [英] .NET Core: Finally block not called on unhandled exception on Linux

查看:33
本文介绍了.NET Core:Linux 上未处理的异常未调用 finally 块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了以下 C# 程序:

I have created the following C# program:

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");
        }
    }
}

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

When I run this using dotnet run, I see the following behavior:

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

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

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

EDITS Clarifications/additions from the conversation below:

  • 这不是 using/Dispose() 特有的,它只是 try/finally 的一个特例.该行为通常也发生在 try/finally 中 - finally 块未运行.我已更新标题以反映这一点.
  • 我还通过将文件写入文件系统来检查 Dispose() 的执行情况,只是为了确保该问题与在 Dispose 之前从控制台断开 stdout 的连接无关() 在未处理异常的情况下运行.行为是一样的.
  • Dispose() 如果异常在应用程序内的任何地方被捕获,就会被调用.当应用程序完全没有处理它时,就会发生这种行为.
  • 在 Windows 上,长间隔不是由于编译延迟.当异常文本写入控制台时,我开始计时.
  • 我最初的实验是在两个平台上做 dotnet run,这意味着分开编译,但我也尝试过在 Windows 上做 dotnet publish 并直接在上面运行输出两个平台,结果相同.唯一的区别是,当直接在 Linux 上运行时,在异常文本之后写入文本Aborted (core dumped)".
  • This is not specific to using/Dispose(), which is just a special case of try/finally. The behavior also occurs generally with try/finally - the finally block is not run. I have updated the title to reflect this.
  • I have also checked for the execution of Dispose() by writing a file to the filesystem, just to ensure that problem wasn't related to stdout being disconnected from the console before Dispose() is run in the case of an unhandled exception. Behavior was the same.
  • Dispose() does get called if the exception is caught anywhere within the application. It's when it goes completely unhandled by the application that this behavior occurs.
  • On Windows, the long gap is not due to compilation delay. I started timing when the exception text was written to the console.
  • My original experiment was doing dotnet run on both platforms, which means separate compilations, but I have also tried by doing dotnet publish on Windows and directly running the output on both platforms, with the same result. The only difference is that, when run directly on Linux, the text "Aborted (core dumped)" is written after the exception text.

版本详情:

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

推荐答案

官方回复 是这是一个预期的行为.

Official response is that this is an expected behavior.

有趣的是,C# 文档try-finally 上的页面 在顶部明确指出这一点(强调我的)

Interestingly enough, the C# doc page on try-finally explicitly calls this out right at the top (emphasis mine)

在处理的异常中,保证运行关联的 finally 块.但是,如果异常未处理,finally 块的执行取决于异常展开操作的触发方式.这又取决于您的计算机的设置方式.有关详细信息,请参阅 CLR 中未处理的异常处理.

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

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

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

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

One thing I found in my experimentation is that it doesn't appear to be enough to catch the exception, you have to handle it as well. If execution leaves the catch block via a throw, the finally will not run.

这篇关于.NET Core:Linux 上未处理的异常未调用 finally 块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆