作为研究以下问题的结果: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/

10-10 12:36