【问题标题】:why does removing "throw" statement cause "use of unassigned local variable" compilation error?为什么删除“throw”语句会导致“使用未分配的局部变量”编译错误?
【发布时间】:2015-10-01 10:49:44
【问题描述】:

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

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

那么这背后的解释是什么?

【问题讨论】:

    标签: c# .net undefined


    【解决方案1】:

    编译器发现你的代码有可能到达该行

    return foo;
    

    没有进行实际分配。这是如何发生的:

    • 您进入try 块并调用GetFoo()
    • GetFoo() 抛出异常
    • 你捕捉到异常并调用DbHandler.LogException(e);
    • 一旦DbHandler.LogException(e); 返回,你的方法就到达return foo

    在存在throw 行的情况下,当输入catch 块时,return foo 变得无法访问,从而解决了问题。

    【讨论】:

      【解决方案2】:

      我们知道在 C# 中局部变量没有默认值,这 与被赋值为 null 不同。

      这是不正确的。声明一个变量,即使没有实例化它也会分配默认值,null 用于引用类型,default(T) 用于值类型。

      只是我们似乎无法弄清楚为什么要取消投掷 声明导致了这种行为。

      发生这种情况是因为编译器现在推断存在一个未分配 Foo 的执行路径。

      假设发生以下情况:

      1. 您进入try 块,GetFoo 抛出。
      2. 您捕获异常并记录它。如果你throw,那么异常会开始破坏调用堆栈以找到合适的catch 处理程序。如果你不抛出,在这种情况下你只需返回一个null 值。

      编译器试图通过显式让您将 Foo 设置为 null 来阻止您这样做,因为它试图让您意识到这一点并可能防止出现错误。

      Eric Lippert 在Why are local variables definitely assigned in unreachable statements? 中谈到了这一点:

      我们之所以要将其设为非法,并不像许多人认为的那样,因为局部变量将被初始化为垃圾,我们希望保护您免受垃圾的侵害。 事实上,我们会自动将局部变量初始化为它们的默认值。(尽管 C 和 C++ 编程语言不会,并且很乐意让您从未初始化的局部变量中读取垃圾。)相反,它是因为这样的代码路径的存在很可能是一个bug,我们想把你扔进质量的坑里;你应该努力写出那个错误。”

      请参阅Why do local variables require initialization, but fields do not? 了解更多信息。

      【讨论】:

        猜你喜欢
        • 2012-03-03
        • 2019-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多