【问题标题】:Why is my finally block not working in C#?为什么我的 finally 块在 C# 中不起作用?
【发布时间】:2010-10-15 02:44:52
【问题描述】:

我一直在帮助一位同事调试他们代码中的一些奇怪行为。以下示例说明了这一点:

static void Main(string[] args)
{
    string answer = Sample();
    Console.WriteLine(answer);
}

public static string Sample()
{
    string returnValue = "abc";

    try 
    {
         return returnValue;
    }

    catch (Exception)
    {
         throw;
    }

    finally
    {
         returnValue = "def";
    }
}

这个样本返回了什么?

你会认为由于 finally 块,它返回“def”,但实际上,它返回“abc”?我已经单步执行了代码并确认 finally 块实际上被调用了。

真正的答案是你一开始就不应该写这样的代码,但我仍然对这种行为感到困惑。

编辑:根据一些答案澄清流程。

当你单步执行代码时,finally 在 return 之前执行。

重复: What really happens in a try { return x; } finally { x = null; } statement?

【问题讨论】:

    标签: c# finally


    【解决方案1】:

    您的“finally”块正在为 returnValue 分配一个值,而不是实际返回一个值。在 finally 块更改值之前“返回”已经发生,因此返回“abc”。

    虽然代码令人困惑,因为您所做的没有意义,但它所做的却是正确的。

    【讨论】:

    • 这是错误的。如果 return 语句在 try 块内,则 finally 块(如果存在)将在控制返回调用方法之前执行。
    • TStamper - 当变量仍然是“abc”时,在尝试中评估返回值,然后最终执行并更改变量分配,但不是已经缓存的要返回的内容。
    • 是的,但措辞是错误的。从他所说的代码不会继续在示例函数中运行
    【解决方案2】:

    是的,finally 块在函数返回后运行,但这无关紧要。请记住,返回值是按值传递的,因此在返回时会为其创建一个新的临时变量,因此 finally 块不会影响实际返回值。如果您想支持所需的行为,您可以使用 out 参数,如下所示:

    static void Main(string[] args)
    {
        string answer;
        Sample(out answer);
        Console.WriteLine(answer);
    }
    
    public static void Sample(out string answer)
    {
    
        try
        {
            answer = "abc";
            return;
        }
    
        catch (Exception)
        {
            throw;
        }
    
        finally
        {
            answer = "def";
        }
    }
    

    或者,您可以简单地将 return 语句移到 try 块之外,如下所示:

    static void Main(string[] args)
    {
        string answer = Sample();
        Console.WriteLine(answer);
    }
    
    public static string Sample()
    {
        string returnValue;
        try
        {
            returnValue = "abc";
        }
    
        catch (Exception)
        {
            throw;
        }
    
        finally
        {
            returnValue = "def";
        }
    
        return returnValue;
    }
    

    但是,鉴于 finally 块将始终覆盖返回值,这是一个值得怀疑的设计。

    【讨论】:

      【解决方案3】:

      finally 块有效地在return 语句之后运行。因此,在进入 finally 块之前,您已经返回了 abc 的旧值。

      (这并不完全是在引擎盖下的工作方式,但它已经足够接近这里的重点了)

      【讨论】:

        【解决方案4】:

        我不是专家,但我不得不猜测这个函数会返回,并且 then 最终会调用。由于 return returnValue 已经被执行,所以 returnValue 在 finally 块中取什么值并不重要。这种行为是有道理的,因为它 应该在 finally 块之前执行整个 try 块,并且它可以做到这一点的唯一方法是如果它从函数中返回,就像它应该做的那样。

        【讨论】:

          【解决方案5】:

          如果你真的很好奇发生了什么,那么你可以下载并安装Reflector。这是一个很棒的工具,可以放入您的“包 o 技巧”。它会告诉你引擎盖下发生了什么。

          【讨论】:

            【解决方案6】:

            我猜我会说您正在确定在 return 语句所在的位置将返回什么(对字符串“abc”的引用)。

            因此,finally 稍后将该引用设置为引用不同的字符串这一事实对返回值没有影响。

            【讨论】:

              猜你喜欢
              • 2022-01-16
              • 2018-12-28
              • 1970-01-01
              • 2010-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多