由于调查了这个问题:Rethrowing exception in Task doesn't make the Task to go to faulted state,我注意到ThreadAbortException
的一些非常奇怪的行为,我无法理解。
现在,我知道ThreadAbortException
是一种非常特殊的例外。当documentation说出来时,{{3}}非常清楚:
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
一直存在?这是怎么回事?这种行为是否记录在某处?
答案 0 :(得分:1)
该行为是特定于实现的。
来自Ecma-335 VI Annex E, Portability Considerations:
本条款汇集了有关本标准故意为实施留有余地的区域的信息。这个余地旨在允许兼容的实现做出选择,以提供更好的性能或以其他方式增加价值。但这种余地固有地使程序变得不便携。 ......
并进一步(强调我的):
我是。 E. 1无法控制的行为程序行为的以下方面取决于实现。 >这些项目很多 对于编写为>可移植性而设计的代码的程序员来说,这将是熟悉的(例如, 事实上,CLI不会对堆或堆栈施加最小大小)。
- 堆和堆栈的大小不需要具有最小尺寸
醇>相对于异步异常的行为(请参阅System.Thread.Abort)
不支持全球化,因此每个实现都指定其文化信息,包括用户可见的功能,如字符串的排序顺序。
不能假定线程是预先或非预先安排的。该决定是针对具体实施的。
定位程序集是一种特定于实现的机制。
安全策略是一种特定于实现的机制。
文件名是特定于实现的。
计时器分辨率(粒度)是特定于实现的,尽管指定了单位。