【问题标题】:Cannot use variable in while clause that is declared inside the do/while loop不能在 do/while 循环内声明的 while 子句中使用变量
【发布时间】:2015-11-26 20:25:32
【问题描述】:

为什么不允许我使用我在 do 中声明的变量,并在 do/while 循环的 while 部分中使用它?

do
{
   index += index;
   int composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); // cannot resolve symbol composite

第一次看到这个我以为是编译器错误。所以我多次重新启动 Visual Studio,但它仍然无法识别 while 中的变量。

代码有什么问题,还是编译器的错误?

【问题讨论】:

  • 查找变量范围。 composite 只存在于你的 do while 循环范围内,而不存在于它之外。
  • 为什么应该一个超出范围的变量可以在其范围之外使用?如果你能这样做,那将是一个错误
  • @M.kazemAkhgary composite only 存在于(阅读:{ } 内)while 循环中。你试图在循环之外使用它,这是你做不到的。
  • @M.kazemAkhgary 这将打破许多其他范围界定规则。 { } 中定义的东西在它们之外不存在,编译器不应该制造“特殊情况”,通常循环被展开或转换为其他形式,这使得它更加困难。
  • @M.kazemAkhgary 不,它不会。这种行为是不合逻辑的。尝试在其范围之外使用变量是一个明显的错误。事实上,这种任意行为是经典 Visual Basic 的主要痛点之一

标签: c# do-while


【解决方案1】:

您的变量在 do/while 之外使用(在 C# 中,curlies 通常定义范围),并且由于它是在 do-while 内声明的,因此您不能在该范围之外使用它。

您可以通过简单地在循环外声明它来解决此问题。

int composite = 0;   // you are not required to set it to zero, as long 
                     // as you do not use it before you initialize it
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); 

注意(1),通常的做法是一次性声明和设置一个变量,但这不是必须的,只要在使用前设置即可。

注(2):在C#中,大括号{....}定义了变量的作用域。您不能在其范围之外使用变量,它不再“可见”,事实上,一旦超出范围,它就可以被垃圾回收,并且它的内容可以是未定义的。


我知道,但是为什么编译器不能这样做

您在 cmets 中问过这个问题。答案并不像看起来那么简单。它高度依赖于语言定义。某些语言,如 Perl 或更旧的 BASIC,允许在任何级别和任何范围内声明变量。其他语言允许对变量进行范围界定,并要求在使用之前声明变量(C#、Java、C++、Python)。通常,但不一定,这对于statically typed languages 来说很常见,因为编译器需要事先知道你想在变量中放入什么类型的数据,以便进行类型检查

如果编译器强制声明,但不强制作用域,这意味着所有变量都是全局变量,这在大型程序中很难,作为程序员,您必须维护使用变量名的位置并保持唯一性。这非常乏味(想想 COBOL)。

C# 添加了dynamic 关键字,它允许具有动态类型的变量,但这仍然需要您在使用之前定义变量。

编译器可以做到这一点,但 C# 的设计者认为清晰的语言更好,他们认为声明变量are a good thing,因为它可以防止虚假错误和无法遵循的代码:

// can you see the problem?
va1l = 1;
val1 = 2;
vall = va1l + vall;

强制您声明变量并将它们限定范围可防止此类错误和相关类型的错误。

【讨论】:

  • 我认为你的意思是它在“内部”做/当。
  • @juharr,谢谢,但不,我的意思是它在其范围之外使用。我会编辑。
  • 在这种情况下你不需要在循环之前将变量composite初始化为零。
  • @LucaCremonesi:这是正确的。但是由于 OP 写了 “这里有更多代码”,我不确定是否有可能在显示的代码之前出现更多代码。底线,我想防止他的总代码块因“使用未初始化的变量”错误而失败。但我同意,正如所写的那样,不需要初始化它。我已经在该程度上添加了评论。
【解决方案2】:

这不是错误。 while 循环内的条件位于定义变量的块之外。

int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite));

【讨论】:

    【解决方案3】:

    这个变量的作用域就在循环内......你不能在循环外使用它

    你应该这样做......

    int composite;
    do
    {
       index += index;
       composite = index + 1;
       // more code here
    } while (UnsetBitmask(bitmasks, composite)); 
    

    【讨论】:

      【解决方案4】:

      虽然{ ... } 表示代码块,但该块中的所有变量都被限制在该特殊范围内。您的条件不在此范围内,因此无法访问那里的变量。在循环之外声明它并且它可以工作:

      int composite = 0;
      do
      {
          index += index;
          composite += index + 1;
          // more code here
      } while (UnsetBitmask(bitmasks, composite));
      

      【讨论】:

        【解决方案5】:

        根据Specificationdo .. while 的条件变量应在循环外声明,否则在每次迭代中,变量将重新初始化,这没有意义。

                int composite;
                do
                {
                    index += index;
                    composite = index + 1;
                    // more code here
                } while (UnsetBitmask(bitmasks, composite)); 
        

        【讨论】:

          【解决方案6】:

          更多一般规则:你不能在其作用域之外使用变量,它在C#中是{...},例如

            {
             int x = 123;
             ...
            }
            x = 456; // <- compile time error
          

          do {} while 在您的代码中仅表示范围属于循环。

          【讨论】:

            【解决方案7】:

            我知道“while”在块之外,但请考虑一下:

            for (int i = 0; i < 10; i++) 
            {
              Console.WriteLine(i);
            }
            

            这里,变量“i”是块范围的(在 for 块之外不可见),实际上在每次循环迭代时都会创建一个新的“实例”。但实际的定义在块之外。

            您可以说“for”声明属于该块,但我会说“while”也属于该块。只是不一致!

            【讨论】:

              【解决方案8】:
                  int composite;
              do
              {
                 index += index;
                 composite = index + 1;
                 // more code here
              } while (UnsetBitmask(bitmasks, composite));
              

              【讨论】:

              • 根据do ehile的格式声明变量必须在开始循环之前完成
              • 您可以编辑您的答案以添加(或更正)信息,而不是添加评论。最好编辑您的答案,因为这样其他人以后可以更轻松地查找和阅读信息。
              猜你喜欢
              • 1970-01-01
              • 2020-05-07
              • 2016-01-24
              • 1970-01-01
              • 2011-12-23
              • 2021-07-18
              • 1970-01-01
              • 2014-03-28
              • 1970-01-01
              相关资源
              最近更新 更多