在项目工作期间,我发现了一些我和我的同事都无法解释的行为。使用的代码简化如下:
public Foo DoSomethingWithFoo()
{
Foo foo;
try
{
foo = GetFoo();
}
catch (Exception e)
{
DbHandler.LogException(e);
throw;
}
return foo;
}
这个编译完全正常,但只要我们删除throw;
语句。我们收到编译错误:Use of unassigned local variable 'foo'
问题不在于解决它,因为我们可以写Foo foo = null;
。
我们知道在C#中,局部变量没有默认值,这与赋值null不同。只是我们似乎无法弄清楚为什么删除throw语句会导致这种行为。虽然我确实找到了一些关于未定义变量的更多信息,但我还没有找到任何解释这个的东西。
那背后的解释是什么?
答案 0 :(得分:10)
编译器发现您的代码可能会到达
行return foo;
没有进行实际分配。以下是它可能发生的方式:
try
块并致电GetFoo()
GetFoo()
抛出异常DbHandler.LogException(e);
DbHandler.LogException(e);
返回,您的方法就会到达return foo
如果出现throw
行,则在输入return foo
块时无法访问catch
,从而解决问题。
答案 1 :(得分:6)
我们知道在C#中局部变量没有默认值,其中 不同于被指定为null。
那是不对的。声明变量,即使没有实例化,也会为引用类型分配默认值null
,为值类型分配default(T)
。
只是我们似乎无法弄清楚为什么要删除投掷 声明引起了这种行为。
这是因为编译器现在推断存在未分配Foo
的执行路径。
假设发生以下情况:
try
块,GetFoo
抛出。throw
,则异常开始撕掉调用堆栈以找到合适的catch
处理程序。如果你不扔,你只需在这种情况下返回null
值。 编译器试图通过明确地将Foo
设置为null来阻止您这样做,因为它试图让您意识到这一点并且可能会阻止错误。 < / p>
Eric Lippert在Why are local variables definitely assigned in unreachable statements?中讨论了这个问题:
我们想让这个非法的原因并不像许多人所认为的那样,因为本地变量将被初始化为垃圾,我们希望保护您免受垃圾侵害。 我们实际上会自动将本地化初始化为默认值。(虽然C和C ++编程语言没有,并且会高兴地允许您从未初始化的本地读取垃圾。)相反,它是因为这样的代码路径的存在可能是一个错误,我们想把你扔进质量的坑中;你应该努力写出那个bug。&#34;
有关详情,请参阅Why do local variables require initialization, but fields do not?。