6

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

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 在返回之前执行。

重复: 在 try { return x; 中真正发生了什么 } 最后 { x = null; } 陈述?

4

6 回答 6

12

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

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

于 2009-03-24T00:41:04.713 回答
3

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

(这并不完全是引擎盖下的工作方式,但对于这里的观点来说已经足够接近了)

于 2009-03-24T00:43:06.783 回答
3

是的,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 块将始终覆盖返回值,这是一个有问题的设计。

于 2009-03-24T00:58:32.470 回答
0

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

于 2009-03-24T00:42:49.030 回答
0

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

于 2009-03-24T00:44:15.283 回答
0

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

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

于 2009-03-24T00:45:23.393 回答