为什么删除“throw”语句导致“使用未分配的局部变量”编译错误?

时间:2015-10-01 10:49:45

标签: c# .net undefined

在项目工作期间,我发现了一些我和我的同事都无法解释的行为。使用的代码简化如下:

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语句会导致这种行为。虽然我确实找到了一些关于未定义变量的更多信息,但我还没有找到任何解释这个的东西。

那背后的解释是什么?

2 个答案:

答案 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的执行路径。

假设发生以下情况:

  1. 您输入try块,GetFoo抛出。
  2. 您捕获异常并记录它。如果你throw,则异常开始撕掉调用堆栈以找到合适的catch处理程序。如果你不扔,你只需在这种情况下返回null值。
  3. 编译器试图通过明确地将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?