作为研究以下问题的结果:Rethrowing exception in Task doesn't make the Task to go to faulted state,我注意到了我无法理解的ThreadAbortException
某些非常奇怪的行为。
现在,我知道ThreadAbortException
是一种非常特殊的异常。当documentation说的很清楚时:
ThreadAbortException
是可以捕获的特殊异常,但是会在catch
块的结尾自动再次引发。
方案1:已记录的行为。
static void Main(string[] args)
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
}
Console.WriteLine("will never be reached");
}
如预期的那样,
ThreadAbortException
将自动重新抛出,从而产生以下输出:caught exception: ThreadAbortException
场景2:当我决定在
catch
块中引发另一个异常时,它会变得有趣起来:static void Main(string[] args)
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
throw new ApplicationException(); // will ThreadAbortException take precedence?
}
Console.WriteLine("will never be reached");
}
在这种情况下,我假设尽管抛出了
ApplicationException
,但是无论如何都将ThreadAbortException
重新抛出以确保保留记录的行为。令我惊讶的是,结果是:caught exception: ThreadAbortException
Unhandled Exception: System.ApplicationException: Error in the application.
at ConsoleApplication1.Program.Main(String[] args) in C:\projects\ConsoleApplication1\Program.cs:line 193
ApplicationException
实际替换并防止了ThreadAbortException
被抛出吗?!?场景3:最后,为了使事情变得更有趣,我在现有的异常处理中添加了另外一个
try-catch
层:static void Main(string[] args)
{
try
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
throw new ApplicationException();
}
}
catch (Exception outerEx)
{
Console.WriteLine("caught outer exception: " + outerEx.GetType().Name);
}
Console.WriteLine("will never be reached");
}
现在我不太确定会发生什么。哪个异常将在外部
catch
块中捕获?会是ApplicationException
吗?如果是这样,这是否意味着我将能够吞下该异常并实际上设法打印出will never be reached
字符串?这是实际输出:
caught exception: ThreadAbortException
caught outer exception: ApplicationException
从上面的输出中,似乎外部
catch
块确实捕获了ApplicationException
。但是,在该catch
块结束时,ThreadAbortException
现在突然间突然消失了,被扔了吗?问题:有人可以解释和调解方案2和方案3吗?在场景2中,
ThreadAbortException
意外地被另一个异常替换了,这又是怎么回事?但是,在场景3中,ThreadAbortException
似乎一直都存在吗?这是怎么回事?此行为记录在某处吗? 最佳答案
该行为是特定于实现的。
从Ecma-335 VI Annex E, Portability Considerations:
本条款收集有关本标准故意留给实施留有余地的信息。此余地旨在允许兼容的实现方案做出选择,以提供更好的性能或以其他方式增加价值。但是,这种保留方式固有地使程序不可移植。 ...
进一步(强调我的):
我E. 1不可控制的行为
程序行为的以下方面取决于实现。 >其中许多项目
习惯于编写针对可移植性设计的代码的程序员会很熟悉(例如,
CLI并未对堆或堆栈施加最小大小的事实)。
不需要堆和栈的大小具有最小大小
与异步异常有关的行为(请参阅System.Thread.Abort)
不支持全球化,因此每个实现都指定其区域性信息,包括诸如字符串排序顺序之类的用户可见功能。
不能假定线程是抢先调度或非抢先调度的。该决定是针对具体实施的。
定位程序集是特定于实现的机制。
安全策略是特定于实现的机制。
文件名是特定于实现的。
尽管指定了单位,但计时器分辨率(粒度)是特定于实现的。
关于c# - 奇怪的行为:捕获ThreadAbortException并引发其他异常,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31576577/