【问题标题】:How code below the finally block execute?finally 块下面的代码如何执行?
【发布时间】:2021-06-21 18:32:44
【问题描述】:

我找不到任何微软官方资源显示 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# .net exception


    【解决方案1】:

    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");
        }
    

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

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

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

    【讨论】:

    • @Lopop 感谢您的回答,但为什么要打印“SomeMethod1 last”?
    • @amjad 我对帖子的末尾进行了编辑,这可能为时已晚。但原因是因为 SomeMethod2 正在捕获异常。一旦捕获到异常,它就不会继续向上调用堆栈。通过像你一样捕捉它,你实际上是在说“我可以处理这个,不要让其他人知道发生了这个异常”,这就是 SomeMethod1 不受该异常影响的原因。
    • 谢谢。我现在看到了,但不明白为什么没有任何官方的微软资源提到它,他们所有的例子在 finally 块下面都没有代码。
    • 在此处查看此文档...虽然他们没有在 finally 下方添加任何代码,但它们确实包含了一个注释,该注释引用了在 finally 之后运行的更多代码。 docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多