gpt4 book ai didi

c# - 在 finally block 中将未处理的异常更改为已处理的异常

转载 作者:太空狗 更新时间:2023-10-29 21:53:56 26 4
gpt4 key购买 nike

考虑这个程序:

using System;
static class Program {
static void Main(string[] args) {
try {
try { throw new A(); }
finally { throw new B(); }
}
catch (B) { }
Console.WriteLine("All done!");
}
}

class A : Exception { }

class B : Exception { }

此处,抛出类型为 A 的异常,没有处理程序。在 finally block 中,抛出类型为 B 的异常,该异常有一个处理程序。通常,在 finally block 中抛出的异常会获胜,但对于未处理的异常则不同。

调试时,调试器在抛出A时停止执行,并且不允许执行finally block 。

当不调试时(从命令提示符独立运行),会显示(打印和崩溃对话框)关于未处理异常的消息,但在那之后,“全部完成!”确实得到打印。

当添加一个顶层异常处理程序时,除了重新抛出捕获的异常外,一切都很好:没有意外消息,并且“全部完成!”打印出来。

我明白这是怎么发生的:在执行任何 finally block 之前确定异常是否有处理程序。这通常是可取的,并且当前的行为是有道理的。 finally block 通常不应抛出异常。

但是this other Stack Overflow question引用 C# 语言规范并声称需要 finally block 来覆盖 A 异常。阅读规范,我同意这正是它所需要的:

  • In the current function member, each try statement that encloses the throw point is examined. For each statement S, starting with the innermost try statement and ending with the outermost try statement, the following steps are evaluated:
    • If the try block of S encloses the throw point and if S has one or more catch clauses, the catch clauses are examined [...]
    • Otherwise, if the try block or a catch block of S encloses the throw point and if S has a finally block, control is transferred to the finally block. If the finally block throws another exception, processing of the current exception is terminated. Otherwise, when control reaches the end point of the finally block, processing of the current exception is continued.
  • If an exception handler was not located in the current function invocation, the function invocation is terminated, and one of the following occurs:
    • [...]
  • If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. The impact of such termination is implementation-defined.

根据我对规范的阅读,异常不会被视为未处理,直到之后所有函数调用都已终止,并且函数调用不会终止直到finally 处理程序已执行。

我是不是遗漏了什么,或者微软的 C# 实现与他们自己的规范不一致?

最佳答案

我认为问题在于 .NET 异常处理是如何构建在结构化异常处理之上的,后者对于在 finally block 中抛出的规则略有不同。

当异常 A 发生时,SEH 尝试找到第一个能够处理您的异常类型的处理程序,然后开始运行所有 finally block ,展开到它,但是基于 SEH 逻辑,没有这样的处理程序,因此它会在之前哭诉未处理的异常.NET 可以执行自己的规则。

这解释了修复问题的顶级处理程序(但只是可以处理异常类型 A 的处理程序)。

IL 本身看起来有效:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size 49 (0x31)
.maxstack 1
IL_0000: nop
IL_0001: nop
.try
{
IL_0002: nop
.try
{
IL_0003: nop
IL_0004: newobj instance void A::.ctor()
IL_0009: throw
} // end .try
finally
{
IL_000a: nop
IL_000b: newobj instance void B::.ctor()
IL_0010: throw
} // end handler
} // end .try
catch B
{
IL_0011: pop
IL_0012: nop
IL_0013: ldstr "B"
IL_0018: call void [mscorlib]System.Console::WriteLine(string)
IL_001d: nop
IL_001e: nop
IL_001f: leave.s IL_0021
} // end handler
IL_0021: nop
IL_0022: nop
IL_0023: nop
IL_0024: ldstr "A"
IL_0029: call void [mscorlib]System.Console::WriteLine(string)
IL_002e: nop
IL_002f: nop
IL_0030: ret
} // end of method Program::Main

Mono有同样的问题http://ideone.com/VVoPx6

关于c# - 在 finally block 中将未处理的异常更改为已处理的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27017971/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com