C#最终执行时间
以这个代码为例:C#最终执行时间,c#,exception,finally,C#,Exception,Finally,以这个代码为例: using System; namespace OddThrow { class Program { static void Main(string[] args) { try { throw new Exception("Exception!"); } finally {
using System;
namespace OddThrow
{
class Program
{
static void Main(string[] args)
{
try
{
throw new Exception("Exception!");
}
finally
{
System.Threading.Thread.Sleep(2500);
Console.Error.WriteLine("I'm dying!");
System.Threading.Thread.Sleep(2500);
}
}
}
}
这给了我这个输出:
Unhandled Exception: System.Exception: Exception!
at OddThrow.Program.Main(String[] args) in C:\Documents and Settings\username
\My Documents\Visual Studio 2008\Projects\OddThrow\OddThrow\Program.cs:line 14
I'm dying!
我的问题是:为什么未处理的异常文本出现在finally之前?在我看来,finally应该在堆栈展开时执行,甚至在我们知道这个异常没有处理之前。请注意对Sleep()的调用-这些调用发生在打印未处理的异常之后,就像它正在执行以下操作一样:
- 在当前函数成员中,将检查包含抛出点的每个try语句。对于每个语句,从最内层的try语句开始,到最外层的try语句结束,将计算以下步骤:
- 如果S的try块包含抛出点,并且S有一个或多个catch子句,则将按外观顺序检查catch子句,以找到适合异常的处理程序。指定异常类型或异常类型的基类型的第一个catch子句被视为匹配。一般捕获条款(§8.10)被视为与任何例外类型相匹配。如果找到了匹配的catch子句,则通过将控制权转移到该catch子句的块来完成异常传播
- 否则,如果S的try块或catch块包含抛出点,并且S有finally块,则控制权转移到finally块。如果finally块引发另一个异常,则终止当前异常的处理。否则,当控件到达finally块的端点时,将继续处理当前异常
- 如果异常处理程序未位于当前函数成员调用中,则函数成员调用将终止。然后对函数成员的调用方重复上述步骤,抛出点对应于调用函数成员的语句
- 如果异常处理终止当前线程中的所有函数成员调用,表明该线程没有异常处理程序,则该线程本身终止。此类终止的影响由实施定义
我哪里做错了?(我有一些自定义的控制台错误消息,这是一个障碍。轻微的,只是令人讨厌,让我对语言产生疑问…如果在某个点被捕获,try-catch-finally块的工作与您预期的完全一样。当我为此编写一个测试程序时,我使用了各种嵌套级别,它的行为方式与您所描述的方式相匹配的唯一情况是,异常完全没有被代码处理,并且冒泡到操作系统中 每次我运行它时,都是操作系统创建了错误消息。 所以问题不在于C#,而在于未经用户代码处理的错误不再在应用程序的控制之下,因此运行时(我相信)无法对其强制执行模式 如果您创建了一个windows窗体应用程序,并将所有消息写入一个文本框(然后立即刷新),而不是直接写入控制台,那么您根本不会看到该错误消息,因为它是由调用应用程序插入错误控制台的,而不是由您自己的代码插入的 编辑
我将努力强调其中的关键部分。未处理的异常超出您的控制范围,您无法确定何时执行它们的异常处理程序。如果您在应用程序中的某个点捕获到异常,那么
finally
块将在堆栈中较低的catch
块之前执行。我读取内容的方式可能会偏离基准……但是您有一个try finally块,而没有catch
根据您发布的描述,由于从未捕获异常,因此它会冒泡到调用方,在堆栈中运行,最终未处理,调用终止,然后调用finally块。输出实际上来自默认的CLR异常处理程序。异常处理程序发生在finally块之前。在finally块之后,CLR由于未处理的异常而终止(它不能在之前终止,因为c#保证[1]调用finally子句) 所以我想说这只是标准行为,异常处理在最终发生之前就发生了
[1] 保证在正常运行期间,至少在没有内部运行时错误或断电的情况下,try/finally不带catch将使用默认的处理程序,该处理程序会完全按照您看到的执行。我一直都在使用它,例如,在处理异常时会覆盖一个错误,但仍然需要进行一些清理的情况下
还请记住,标准错误和标准输出的输出是缓冲的。虽然不是完全预期的,但程序确实按其应有的方式运行。finally块不应首先运行,而应始终运行 我调整了你的样品:
public static void Main()
{
try
{
Console.WriteLine("Before throwing");
throw new Exception("Exception!");
}
finally
{
Console.WriteLine("In finally");
Console.ReadLine();
}
}
在这种情况下,您将得到讨厌的未处理异常对话框,但之后控制台将输出并等待输入,从而执行最后的,而不是之前的Windows本身捕获未处理的异常。
< P>在混合中添加更多,请考虑如下:using System;
namespace OddThrow
{
class Program
{
static void Main()
{
AppDomain.CurrentDomain.UnhandledException +=
delegate(object sender, UnhandledExceptionEventArgs e)
{
Console.Out.WriteLine("In AppDomain.UnhandledException");
};
try
{
throw new Exception("Exception!");
}
catch
{
Console.Error.WriteLine("In catch");
throw;
}
finally
{
Console.Error.WriteLine("In finally");
}
}
}
}
在我的系统(挪威语)上显示:
[C:\..] ConsoleApplication5.exe
In catch
In AppDomain.UnhandledException
Ubehandlet unntak: System.Exception: Exception!
ved OddThrow.Program.Main() i ..\Program.cs:linje 24
In finally
本标准关于执行顺序的陈述是正确的,并且与您所观察到的内容不一致。“未处理的异常”消息允许出现在流程中的任何点,因为它只是来自CLR的消息,而不是异常处理程序本身。关于执行顺序的规则仅适用于CLR内部执行的代码,而不适用于CLR本身的功能 实际上,您所做的是公开一个实现