为什么我的finally块不能在C#中工作?

时间:2009-03-24 00:36:15

标签: c# finally

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

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块实际上已被调用。

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

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

当您单步执行代码时,最终会在返回之前执行。

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

7 个答案:

答案 0 :(得分:12)

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

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

答案 1 :(得分:3)

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

(这不完全是如何在幕后工作,但它足够接近这一点)

答案 2 :(得分: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块将始终覆盖返回值,这是一个值得怀疑的设计。

答案 3 :(得分:2)

前段时间发现了this链接,处理了这个问题。他遇到了显示IL代码的麻烦,这些代码正好将正在发生的事情带回家。

答案 4 :(得分:0)

我不是专家,但我不得不猜测这个函数会返回,然后然后会调用。由于return returnValue已经被执行,因此returnValue在finally块中的值是什么并不重要。这种行为是有道理的,因为它 应该在finally块之前执行整个try块,并且它能做到的唯一方法就是它从函数返回它应该如此。 / p>

答案 5 :(得分:0)

如果您对发生的事情非常好奇,那么您可以下载并安装Reflector。这是一个很棒的工具,可以放入你的'包诀'。它会告诉你底层发生了什么。

答案 6 :(得分:0)

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

因此,最后稍后设置引用引用不同字符串的事实对返回值没有影响。