【问题标题】:Why does this "finally" execute?为什么这个“最终”执行?
【发布时间】:2010-11-11 14:34:28
【问题描述】:

如果你运行下面的代码,它实际上会在每次调用 goto 之后执行 finally:

    int i = 0;
Found:
    i++;
    try
    {
        throw new Exception();
    }
    catch (Exception)
    {
        goto Found;
    }
    finally
    {
        Console.Write("{0}\t", i);
    }

为什么?

【问题讨论】:

  • -1 用于使用 GOTO
  • 我没有在生产代码中这样做。这只是一种假设情况。
  • 投反对票的主要原因:在获得超过 4k 积分后,我认为这是一个菜鸟问题!!!对不起... :)
  • 既然你知道了答案,你就可以解决这个难题了:给我写一个程序,其中有一个可到达的 goto,它指向一个不可到达的标签。
  • -1 用于使用 GOTO,真的吗?这一点都不傻。

标签: c# exception goto try-catch-finally


【解决方案1】:

为什么你认为它不会执行?

如果你有 try/catch/finally 或 try/finally 块,finally 块会执行无论你在 try 或 catch 块中有什么代码 most of the time

考虑“返回”,而不是 goto。

//imagine this try/catch/finally block is inside a function with return type of bool. 
try
{
    throw new Exception();
}
catch (Exception)
{
    return false; //Let's say you put a return here, finally block still executes.
}
finally
{
    Console.WriteLine("I am in finally!");
}

【讨论】:

  • 如果你有一个'return true;'会发生什么在 finally 块中(针对上面的示例代码)。返回什么?是真还是假?
  • @Pure.Krome,您不能将 return 语句放在 finally 块中。
  • @Pure.Krome,正如 Jonathon Watney 所说,您将收到“编译器错误 CS0157:控件无法离开 finally 子句的主体”。
  • 你们也可以看看 Eric Lippert 的博客文章。这就是我从那里得到问题的地方。 blogs.msdn.com/ericlippert/archive/2009/07/16/…
  • SO 问题的链接似乎已失效。
【解决方案2】:

这是设计使然。在异常处理程序中,您可以采取一些特定于异常的操作。在 finally 块中,您应该进行资源清理 - 这就是为什么无论异常处理代码是什么,都会始终执行 finally 块的原因。

【讨论】:

    【解决方案3】:

    看起来很合理。 finally 块总是在 trycatch 之后运行。

    同样

    try
    {
      // do something
      return;
    }
    finally
    {
      // do something else
    }
    

    将始终运行 finally 块。编辑 - 但请参阅上面 Eric 的 cmets。

    【讨论】:

      【解决方案4】:

      因为finally 语句预计在离开try(或catch 捕获异常时)后执行。这包括您进行 goto 调用的时间。

      【讨论】:

        【解决方案5】:

        以下文字来自C#语言规范 (8.9.3 The goto statement)


        goto 语句执行如下:

        • 如果 goto 语句退出一个或多个带有关联 finally 块的 try 块,则控制最初会转移到最里面的 try 语句的 finally 块。当控制到达 finally 块的终点时,控制将转移到下一个封闭 try 语句的 finally 块。重复此过程,直到所有介入的 try 语句的 finally 块都已执行。
        • 控制转移到 goto 语句的目标。

        【讨论】:

          【解决方案6】:

          正如人们所提到的,finally 无论程序流程如何都会运行。当然,finally 块是可选的,所以如果你不需要它,就不要使用它。

          【讨论】:

            【解决方案7】:

            给出的答案的要点 - 当控制通过任何方式离开受保护区域时,无论是“return”、“goto”、“break”、“continue”还是“throw”,都会执行“finally”正确的。但是,我注意到几乎每个答案都说“finally 块总是运行”。 finally 块并不总是运行。 finally 块不运行的情况有很多。

            谁想尝试将它们全部列出?

            【讨论】:

            • 根据规范“finally块的语句总是在控制离开try语句时执行。无论控制转移是正常执行的结果,还是执行a的结果,都是如此。 break、continue、goto 或 return 语句,或作为从 try 语句传播异常的结果。”但是,我会说 StackOverflowException 是一个,因为据我所知,没有什么可以处理它。
            • 科林,确实,关键是控制权何时离开。如果控制没有离开,那么 finally 块不会执行!例如,受尝试保护的区域可能包含无限循环。
            • @Eric:我完全从你的博文中得到了这个问题。我也没有想到 try/catch 块中的无限循环
            • Environment.FailFast();和 OutOfMemoryException 都将避免运行 finally 块。
            • @neilwhitaker1:当其中一件事情发生时,控制真的会离开 finally 块,还是控制会直接死掉?如果说“控制不会在 finally 块之外的任何地方而不先执行它,没有操作系统杀死或接管线程并将“控制流”的概念抛到窗外?
            【解决方案8】:

            这就是finally 块的意义所在。它总是执行(几乎)。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-01-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-07-01
              相关资源
              最近更新 更多