首页 > 解决方案 > finally 块下面的代码如何执行?

问题描述

我找不到任何微软官方资源来显示 finally 块下面的代码是如何执行的,关于它的唯一信息是通过 C# 编写的书 CLR,作者说:

如果在 try 块中没有抛出异常,或者如果 catch 块捕获异常并且不抛出或重新抛出异常,则 finally 块下面的代码将执行。

假设我们有以下代码:

class Program {
   static void Main(string[] args) {
      SomeMethod1();
      Console.ReadLine();
   }

   static void SomeMethod1() {
      try {
         SomeMethod2();
      }
      finally {
         Console.WriteLine("SomeMethod1 finally");
      }
      Console.WriteLine("SomeMethod1 last");
   }

   static void SomeMethod2() {
      try {
         SomeMethod3();
      }
      catch (DivideByZeroException e) {
         Console.WriteLine("SomeMethod2 caught");
      }
      finally {
         Console.WriteLine("SomeMethod2 finally");
      }
      Console.WriteLine("SomeMethod2 last");
   }

   static void SomeMethod3() {
      try {
         SomeMethod4();
      }
      finally {
         Console.WriteLine("SomeMethod3 finally");
      }
      Console.WriteLine("SomeMethod3 last");
   }

   static void SomeMethod4() {
      try {
         Int32 i = 0;
         var c = 3 / i;
      }
      finally {
         Console.WriteLine("SomeMethod4 finally");
      }
      Console.WriteLine("SomeMethod4 last");
   }
}

输出是:

SomeMethod4 finally
SomeMethod3 finally
SomeMethod2 caught
SomeMethod2 finally
SomeMethod2 last
SomeMethod1 finally
SomeMethod1 last

您可以看到“SomeMethod4 last”和“SomeMethod3 last”没有被打印出来。“SomeMethod4 last”不被打印好理解,因为SomeMethod4抛出异常,并且没有catch块来捕获异常,所以不符合作者规定的要求,还算公平。

但是为什么“SomeMethod3 last”没有被打印出来?没有抛出异常SomeMethod3,就像SomeMethod1,那么为什么“SomeMethod1 last”被打印而“SomeMethod3 last”没有?是否有任何 Microsoft 官方资源可以解释其机制?

标签: c#.netexception

解决方案


当抛出异常时SomeMethod4,它会流向调用方法,即SomeMethod3. 把它想象成这样SomeMethod4实际上是内联SomeMethod3的。

    static void SomeMethod3()
    {
        try
        {
            try
            {
                Int32 i = 0;
                var c = 3 / i;
            }
            finally
            {
                Console.WriteLine("SomeMethod4 finally");
            }
            Console.WriteLine("SomeMethod4 last");
        }
        finally
        {
            Console.WriteLine("SomeMethod3 finally");
        }
        Console.WriteLine("SomeMethod3 last");
    }

Last 运行的原因SomeMethod2是因为它是实际捕获异常的部分。

如果你添加一个 catch 到SomeMethod3,你会看到它也SomeMethod3 Last被打印出来了。

异常会中断应用程序的流程,并且在到达 catch 语句之前基本上不会停止返回调用堆栈。从技术上讲,异常被抛出内部SomeMethod1,但它被捕获SomeMethod2意味着异常永远不会到达SomeMethod1


推荐阅读