奇怪的行为:捕获ThreadAbortException并抛出不同的异常

时间:2015-07-23 01:10:15

标签: c# .net exception-handling threadabortexception thread-abort

由于调查了这个问题: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一直存在?这是怎么回事?这种行为是否记录在某处?

1 个答案:

答案 0 :(得分:1)

该行为是特定于实现的。

来自Ecma-335 VI Annex E, Portability Considerations

  

本条款汇集了有关本标准故意为实施留有余地的区域的信息。这个余地旨在允许兼容的实现做出选择,以提供更好的性能或以其他方式增加价值。但这种余地固有地使程序变得不便携。 ......

并进一步(强调我的):

  我是。 E. 1无法控制的行为

     

程序行为的以下方面取决于实现。 >这些项目很多   对于编写为>可移植性而设计的代码的程序员来说,这将是熟悉的(例如,   事实上,CLI不会对堆或堆栈施加最小大小)。

     
      
  1. 堆和堆栈的大小不需要具有最小尺寸
  2.         

    相对于异步异常的行为(请参阅System.Thread.Abort)

         

    不支持全球化,因此每个实现都指定其文化信息,包括用户可见的功能,如字符串的排序顺序。

         

    不能假定线程是预先或非预先安排的。该决定是针对具体实施的。

         

    定位程序集是一种特定于实现的机制。

         

    安全策略是一种特定于实现的机制。

         

    文件名是特定于实现的。

         

    计时器分辨率(粒度)是特定于实现的,尽管指定了单位。