C#异常处理最后在catch块之前阻塞

时间:2018-10-26 14:28:07

标签: c# exception-handling

我对C#中如何引发异常感到非常困惑。如果发生异常,请在try块中, 1.它被扔到捕获块, 2.当且仅当catch块捕获到它时,才会执行finally块。 3.如果catch语句捕获了finally块,则最后执行该块。

但是,当我尝试运行下面的程序时,输出为A,B而不是BA。我的理解是否有问题?谢谢。

class Program
 {
     public static void Main(string[] args)
     {
         try
         {
             int a = 2;
             int b = 10 / a;
             try
             {
                 if (a == 1)
                     a = a / a - a;
                 if (a == 2)
                 {
                     int[] c = { 1 };
                     c[8] = 9;
                 }
             }
             finally
             {
                 Console.WriteLine("A");
             }
        }
        catch (IndexOutOfRangeException e)
        {
             Console.WriteLine("B");
        }
        Console.ReadLine();
    }
 }

异常发生在a == 2中,我知道外部捕获将捕获此异常。但是,最后要先执行吗?有什么原因可以说明这一点?

编辑

从C#文档中我们知道,无论是否发生异常,都将执行finally块。

但是,我的finally块永远不会执行,因此我遇到了运行时错误

class Program
{
    public static void Main(string[] args)
    {
        try
        {
            int a = 2;
            int b = 10 / a;
            try
            {
                if (a == 1)
                    a = a / a - a;
                if (a == 2)
                {
                    int[] c = { 1 };
                    c[8] = 9;
                }
            }
            finally
            {
                Console.WriteLine("A");
            }
        }

        finally{
            Console.WriteLine("finally");
        }

        Console.ReadLine();
    }
}

5 个答案:

答案 0 :(得分:4)

finally在控件出于任何原因离开其附着的try块时执行。不仅是在同一级别上有一个catch块-还是一个fault处理程序(按CLR术语),我认为我们仍然无法在C#中做到这一点。

因此它进入打印finally的{​​{1}},因为控制权离开了该A块。由于外部try块中捕获的异常而将其保留。但是,这不会改变任何时间/顺序。


请注意,如果代码中的任何地方都没有完全捕获到异常,则可能会出现一些奇怪的情况。异常处理分为两个阶段。在第一阶段,它将尝试为异常找到合适的catch子句,其中可能包括执行保护子句(when,C#6及更高版本)。在第二阶段中,它将展开堆栈并根据嵌套要求执行任何catch子句,然后达到定义将处理异常的finally子句的正确级别 1

我认为,在某些环境中,如果第一阶段根本找不到合适的异常处理程序(catch子句) ,则整个托管环境可能会被拆除。在这种情况下,不会执行catch子句。

ECMA C# and Common Language Infrastructure Standards上的MS Partition I.pdf文档中描述了

所有符合CLR标准的必需。第12.4.2.5节规定:

  

发生异常时,CLI   在数组中搜索第一个受保护的块

     
      
  • 保护一个包含当前指令指针

  • 的区域   
  • 是catch处理程序块

  •   
  • 谁的过滤器希望处理异常

  •   
     

如果在当前方法中找不到匹配项,则搜索调用方法,依此类推。 如果找不到匹配项   CLI将转储堆栈跟踪并中止程序。

(我的重点


1 使用Flydog57's example的变体以及C#7局部函数来说明:

finally

此打印:

using System;

namespace PlayAreaCSCon
{
    internal class Program
    {
        static void Main(string[] args)
        {
            TestTryCatchFinally();
            Console.WriteLine("Complete");
            Console.ReadLine();
        }

        private static void TestTryCatchFinally()
        {
            try
            {
                Console.WriteLine("Start Outer Try");
                try
                {
                    Console.WriteLine("Start Inner Try");
                    throw new Exception("Exception from inner try");
                }
                finally
                {
                    Console.WriteLine("In Inner Finally");
                }
            }
            catch (Exception ex) when (GuardHelper(ex))
            {
                Console.WriteLine("In outer catch");
            }
            finally
            {
                Console.WriteLine("In outer finally");
            }

            bool GuardHelper(Exception ex)
            {
                Console.WriteLine("In outer guard");
                return true;
            }
        }
    }
}

说明异常处理的两次通过特性(Start Outer Try Start Inner Try In outer guard In Inner Finally In outer catch In outer finally Complete 之前 In outer guard打印)

答案 1 :(得分:0)

如果您有一个try-catch-finally块,那么将catch放在最后是正确的。但是在这里,try-finally和try-catch块是按照从内到外的顺序运行的。因此,最终运行优先。

答案 2 :(得分:0)

它应该看起来像这样(具体取决于您实际要做什么)

localhost:8080/ShoppingSocieties/Shopping/products/purchase?id=1

答案 3 :(得分:0)

在您的第一个代码中,finally(A)在catch(B)之前运行的原因是,当引发异常时,您退出内部块(导致{{1 }}运行)在外部代码块的finally开始发挥作用之前。考虑以下代码:

catch

如果运行此代码,则会得到以下输出:

private void TestTryCatchFinally()
{
    try
    {
        Debug.WriteLine("Start Outer Try");
        try
        {
            Debug.WriteLine("Start Inner Try");
            throw new Exception("Exception from inner try");
            Debug.WriteLine("End of Inner Try - never reaced");
        }
        //remove this catch block for second test
        catch (Exception)
        {
            Debug.WriteLine("In inner catch");
        }
        //end of code to remove
        finally
        {
            Debug.WriteLine("In Inner Finally");
        }
    }
    catch (Exception)
    {
        Debug.WriteLine("In outer catch");
    }
    finally
    {
        Debug.WriteLine("In outer finally");
    }
}

您期望的是什么。但是,如果删除内部catch块(如代码中所述),则会得到以下输出:

Start Outer Try
Start Inner Try
Exception thrown: 'System.Exception' in MyTestApp.exe
In inner catch
In Inner Finally
In outer finally

在这种情况下,一旦执行退出内部try块,最终代码就会执行。然后外面的挡块轮到了。

答案 4 :(得分:-1)

我可能缺少一些东西。您不需要以下内容吗?

try
{          
}
catch (Exception ex)
{
}
finally
{  
}

通过使用finally{}块,可以确保某些语句将始终运行