c#中的变量范围:未按预期工作

时间:2014-08-29 17:50:54

标签: c# .net scope

考虑这段代码

class Program
{
    static void Main(string[] args)
    {            
        string str;
        int x;

        for (x = 1; x < 10; x++)
        {
            str = "this";
        }

        Console.WriteLine(str);
        Console.ReadLine();
    }
}

当我编译时我得到:错误使用未分配的局部变量&#39; str&#39; (我理解这一部分)

如果我将循环更改为if,那么它可以正常工作。为什么这样(在这里迷茫)??

class Program
{
    static void Main(string[] args)
    {            
        string str;
        int x;

        if (true)
        {
            str = "this";
        }

        Console.WriteLine(str);
        Console.ReadLine();
    }
}

这种不同行为的原因是什么?我预计它应该在两种情况下都给出相同的结果。

我做错了什么?

3 个答案:

答案 0 :(得分:8)

通过静态分析,编译器确定您的if语句将会运行并且str将被分配。

将您的第二个示例更改为

class Program
{
    static void Main(string[] args)
    {            
        string str;
        int x;
        bool b = true; // With "const bool" it would work, though

        if (b)
        {
            str = "this";
        }

        Console.WriteLine(str);
        Console.ReadLine();
    }
}

,您将拥有与for循环相同的行为。

编译器不确定您的for循环是否会被执行,即使知道它将会被执行,这就是为什么它会告诉您有关未分配变量的原因。在这种情况下,更复杂的编译器可能会看到您的变量很好,但处理所有这些情况是一个非常复杂的问题。

如果x是一个常量(在for循环中没有意义,因为你想增加它......)编译器将能够看到1确实小于10并且它不会警告你有关未使用的变量。当然循环现在会永远运行,但我这样说只是为了强调编译器只能确定常量。

答案 1 :(得分:6)

原因是在第一种情况下,编译器会考虑从不执行循环的情况:

for (x = 1; x < 10; x++)
{
    str = "this";
}

因此它假设str可能保持未初始化状态。


在第二种情况下,条件始终为true,因此编译器认为始终初始化str

if (true)
{
    str = "this";
}

答案 2 :(得分:2)

编译器无法确定for循环是否会实际迭代。它可以循环0次。编译器已知if(true)语句无条件执行。

虽然从理论上讲,适当高级的编译器可以推断第一个代码块确实无条件地执行,但在一般情况下解决问题是不可能的(你遇到了停机问题)。编译器被迫使用启发式方法来合理地猜测给定语句是否可达。如果它指出路径无法访问,您可以肯定地知道它无法访问。如果它说它可以到达它可能是可达的,或者它可能是误报。