c#中的变量作用域:未按预期工作

本文关键字:工作 变量 作用域 | 更新日期: 2023-09-27 18:19:58

考虑这个代码

class Program
{
    static void Main(string[] args)
    {            
        string str;
        int x;
        for (x = 1; x < 10; x++)
        {
            str = "this";
        }
        Console.WriteLine(str);
        Console.ReadLine();
    }
}

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

如果我把for循环改为If,那么它工作得很好。为什么这样(这里很困惑)??

class Program
{
    static void Main(string[] args)
    {            
        string str;
        int x;
        if (true)
        {
            str = "this";
        }
        Console.WriteLine(str);
        Console.ReadLine();
    }
}

这种不同行为的原因是什么?。我原以为在这两种情况下都能得到同样的结果。

我做错了什么?

c#中的变量作用域:未按预期工作

通过静态分析,编译器可以确定您的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,并且它不会警告你未使用的变量。当然,现在循环将永远运行,但我这么说只是为了强调编译器只能确定常量。

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

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

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


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

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

编译器不能确定for循环是否会实际迭代。它可以循环0次。if(true)语句对于编译器来说是无条件执行的。

虽然理论上,一个适当高级的编译器可能会认为第一个代码块实际上是无条件执行的,但在一般情况下解决问题是不可能的(你会遇到Halting问题)。编译器被迫使用启发式方法对给定语句是否可访问进行合理的猜测。如果它声明一条路径不可访问,那么你可以肯定地知道它是不可访问的。如果它说它是可以到达的,它可能是可以到达,或者它可能是一个假阳性。