C# .NET内核:在Linux上未处理的异常上未调用最后一个块
我创建了以下C#程序: 当我使用C# .NET内核:在Linux上未处理的异常上未调用最后一个块,c#,linux,.net-core,C#,Linux,.net Core,我创建了以下C#程序: 当我使用dotnet run运行时,我看到以下行为: Windows:异常文本写入控制台,20秒后打印“已处理”,程序退出 Linux:异常文本写入控制台,程序立即退出。“处置”从未写过 Windows上的延迟令人恼火,但Linux上根本没有调用Dispose(),这一事实令人不安。这是预期的行为吗? 编辑以下对话中的澄清/补充: 这并不特定于使用/Dispose()的,这只是try/finally的一个特例。该行为通常也会在try/finally时发生-未运行fi
dotnet run
运行时,我看到以下行为:
- Windows:异常文本写入控制台,20秒后打印“已处理”,程序退出
- Linux:异常文本写入控制台,程序立即退出。“处置”从未写过
- 这并不特定于使用/Dispose()的
,这只是
的一个特例。该行为通常也会在try/finally
时发生-未运行try/finally
块。我更新了标题以反映这一点finally
- 我还通过向文件系统写入一个文件来检查了
的执行情况,只是为了确保在出现未处理的异常情况下运行Dispose()
之前,stdout与控制台断开连接无关。行为是一样的Dispose()
如果在应用程序中的任何位置捕获到异常,则会调用该异常。只有当应用程序完全不处理它时,才会发生这种行为Dispose()
- 在Windows上,长间隔不是由于编译延迟造成的。当异常文本写入控制台时,我开始计时
- 我最初的实验是在两个平台上运行
,这意味着要进行单独的编译,但我也尝试在Windows上运行dotnet
,并在两个平台上直接运行输出,结果相同。唯一的区别是,当直接在Linux上运行时,“中止(内核转储)”文本写在异常文本之后dotnet publish
->1.0.4dotnet--version
- 编译到netcoreapp1.1,在.NET Core1.1上运行
->Ubuntu 16.04.1 LTSlsb发行版-d
- 这是一种预期的行为
有趣的是,在顶部明确地指出了这一点(我的重点)
在已处理的异常中,关联的finally块保证运行但是,如果未处理异常,则finally块的执行取决于异常展开操作的触发方式。这反过来又取决于计算机的设置方式。有关详细信息,请参阅CLR中未处理的异常处理
通常,当未处理的异常结束应用程序时,finally块是否运行并不重要。但是,如果finally块中的语句即使在这种情况下也必须运行,那么一种解决方案是向try finally语句添加catch块。或者,您可以捕获可能在调用堆栈上层的try finally语句的try块中抛出的异常。也就是说,您可以在调用包含try finally语句的方法的方法、调用该方法的方法或调用堆栈中的任何方法中捕获异常如果未捕获异常,finally块的执行取决于操作系统是否选择触发异常解除操作。
我在实验中发现,它似乎不足以捕获异常,您还必须处理它。如果执行通过抛出退出
catch
块,则finally将不会运行。如果使用try-catch将其包围,则当外部catch捕获(处理)异常时,finally块将运行
static void Main(string[] args)
{
try
{
using (var disp = new MyDisposable())
{
throw new Exception("Boom");
}
}
catch (Exception e)
{
throw;
}
}
您应该在异常之前向控制台写入一些内容,以查看20sec延迟是否为编译延迟。您确定没有调用
Dispose
?是否调用了它,但stdout已被分离?您可以尝试使用文件更改控制台.WriteLine
,并查看是否写入了文件。@FedericoDipuma是的,也尝试了,结果相同-文件在Windows上写入,而在Linux上不写入。如果显式使用输出,即使用try/finally
写入,会发生什么情况?如果您添加了一个catch
,以便实际处理异常,会发生什么情况?听起来像是应该报告的错误(例如,通过Connect或GitHub问题)。从您的描述来看,似乎是一个未处理的异常在不展开堆栈的情况下撕裂了进程,即使存在finally
子句。我认为这实际上与IDisposable
关系不大,而与finally
子句(无论它们可能包含什么)的执行不足关系更大。是的,问题范围仅限于未处理的异常。
static void Main(string[] args)
{
try
{
using (var disp = new MyDisposable())
{
throw new Exception("Boom");
}
}
catch (Exception e)
{
throw;
}
}