在 finally 块中使用 return,为什么不行?

24
如MSDN所 提到

当在 Try 或 Catch 块中遇到 Return 语句时,位于 Finally 块中的代码会在该 Return 语句执行之前运行。在这种情况下,Finally 块中的 Return 语句会先执行,导致返回值不同。为了避免这种可能引起混淆的情况,请勿在 Finally 块中使用 Return 语句。

由于我对此笔记并不是很理解,我将以 VB.NET 为例(我认为在 C# 中情况也类似):

Try
    HugeOp()
    Return "OK"
Catch
    Return "NOK"
Finally
    Return "Finally"
End Try

现在,为什么在C#和VB.NET中这样做是不合法的呢?


3
正如我经常建议的那样,只需编写一个小型测试程序来模拟该情况并自己看看即可。 - Dmitry
3
在 C# 中(编辑:似乎在 VB 中也是如此),这是非法的 - Marc Gravell
1
@Mitch Wheat:问题是为什么 - serhio
2
@serhio 啊,那MSDN很令人困惑;在MSDN中更好的注释应该是“避免在Finally块中使用Return语句,否则你的代码将无法编译”;我已经做了这方面的注释。 - Marc Gravell
5
有趣的一点:在JavaScript中这是不违法的。 function m() { try { return 1; } finally { return 2; } } 调用m()将返回2。实现这个功能对于开发团队来说非常棘手。在Java中也是合法的。 - Eric Lippert
显示剩余9条评论
3个回答

34

这是不合法的,因为当你到达Finally块时,返回值已经定义好了(如果一切正常则为“OK”,如果捕获到异常则为“NOK”)。如果你能从Finally块中返回一个不同的值,那么无论上面的指令结果如何,这个值总是会被返回。这就没有意义了...


最后。禁止将代码“去混淆”以确保合法性。谢谢。 - serhio
1
不,返回值是在执行返回语句之前设置的。在这两件事之间,finally块被执行。因此,在finally块中使用返回语句是没有意义的。说finally应该是返回值是没有意义的,因为finally没有返回值。 - izb
@izb:换句话说,在我的成功案例中,编译器将“OK”作为返回值,执行Finally块,然后将“OK”有效地返回? - serhio
12
规范可以定义在 finally 语句中如何处理 return 的行为,可以返回旧的或新的 return 值,或者是非法的。这些行为都是可能的,但规范选择将其视为非法。我同意这个决定。 - CodesInChaos
这与返回值已经设置无关。您可以删除前两个返回语句,但仍会出现相同的错误。 - usr
显示剩余3条评论

2

我很好奇,我正在运行VS2010,但是finally块中不允许使用Return。以下是我编译的代码:

Public Class Class1
   Public Shared Function test() As String
      Try
         Return "OK"
      Catch ex As Exception
         Return "Catch"
      Finally
         test = "Finally"
      End Try
   End Function
End Class

我编译了DLL文件以查看MSIL,发现它非常有趣。上面的代码基本上被重构为以下内容:

Public Class Class2
   Public Shared Function test() As String
      Try
         Try
            test = "OK"
         Catch ex As Exception
            test = "Catch"
         End Try
      Finally
         test = "Finally"
      End Try

      Return test
   End Function
End Class

测试后发现,上述两个类的 MSIL 完全相同。


所以,最终你找到了一种方法在Visual Basic的finally块中使用函数名返回,即使有些困惑,也有办法做到... - serhio

1
我想答案就在问题里。这是非法的,因为它很混乱。人们无法直观地了解哪个值会被返回。如果这是非法的,你将被迫编写代码,流程更加清晰。

"令人困惑","直观",但实际上在编译器规则之后应该返回什么呢?它总是"Finally"吗? - serhio
1
看起来编译器规则表明这是非法的,不应该被编译。因此,问题是它返回什么毫无意义。 - CodesInChaos
@CodeInChaos:请阅读我发布的注释。“这会返回不同的值。” - serhio
你的注释显然是不准确的,也没有描述C#或VB.net的行为。这就是为什么@MarcGravell建议更新文档以使其与编译器的实际行为一致。 - CodesInChaos
@CodeInChaos:我不确定在Visual Studio中这种“错误”是否可以被“降级”为警告... - serhio
2
将其设置为警告将违反规范。 “8.9.4返回语句”-“在finally块中出现返回语句是编译时错误”(来自C#规范) - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接