我一直在帮助同事在他们的代码中调试一些奇怪的行为。以下示例说明了这一点:
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?
答案 0 :(得分:12)
你的“finally”块正在为returnValue赋值,而不是实际返回一个值。
虽然代码令人困惑,因为你所做的事情没有意义,但它正在做的是正确的。
答案 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”的引用)。
因此,最后稍后设置引用引用不同字符串的事实对返回值没有影响。