【问题标题】:How to reference a variable outside of scope in C#如何在 C# 中引用范围之外的变量
【发布时间】:2016-09-01 01:59:09
【问题描述】:

我的教授要求我们创建一个程序,该程序接收用户的身高和体重,然后计算 bmi。我决定更进一步,并添加一些“输入验证”逻辑。这意味着如果有人输入“猫”作为他们的体重,它会让用户知道“猫”不是有效的体重。

class MainClass
{
    public static void Main ()
    {
        float userWeight;
        float userHeight;           
        bool weight = true;
        Console.Write ("Weight:  ");
        while (weight) 
        {               
            var inputWeight = (Console.ReadLine ());
            if (!float.TryParse (inputWeight, out userWeight)) {
                Console.WriteLine ("Invalid input");
                Console.Write ("Please try again: ");
            } 
            else 
            {
                weight = false;
            }
        }
        bool height = true;
        Console.Write ("Height:  ");
        while (height) 
        {
            var inputHeight = (Console.ReadLine ());
            if (!float.TryParse (inputHeight, out userHeight)) {
                Console.WriteLine ("Invalid input");
                Console.Write ("Please try again: ");
            } 
            else 
            {
                height = false;
            }
        }
        float bmiHeight = userHeight * userHeight; // error for userHeight
        float bmi = userWeight / bmiHeight * 703;  // error for userWeight
        Console.WriteLine ("You BMI is " + bmi);
    }           
}

我得到的错误是“使用未分配的局部变量..”。我知道我在 IF 语句中分配用户变量,并且它们只会持续到该 IF 语句结束。

我的问题是,如何在 if 语句中分配一个变量,然后在该语句之外引用该变量的新值?

当然,我不必将它们全部嵌套,因为这看起来很乏味......

【问题讨论】:

    标签: c# variables if-statement scope


    【解决方案1】:

    这里的问题是您的变量 userHeightuserWeight 有可能仍然持有垃圾值,因为您没有初始化它们。

    您可以尝试使用默认有效值来初始化它们:

    float userHeight = DEFAULT_HEIGHT;
    float userWeight = DEFAULT_WEIGHT;
    

    【讨论】:

    • 如果您实际查看代码,这是错误的陈述。虽然在这种特殊情况下初始化值的建议很好,但没有必要,因为有更好的方法可以用不同的代码表达相同的意图。
    • 是的,根据代码,变量最终会被初始化,但编译器不够聪明,无法实现这一点。是的,确实有更好的方法来编写这样的代码
    • 将我的 userWeight 和 userHeight 变量设置为 0 有效!谢谢!
    【解决方案2】:

    Do ... while(condition) 更适合您的情况,还允许编译器确认实际分配了值:

        var isHeightValid = false;
        do 
        {
            var inputHeight = (Console.ReadLine ());
            if (!float.TryParse (inputHeight, out userHeight)) {
                Console.WriteLine ("Invalid input");
                Console.Write ("Please try again: ");
            } 
            else 
            {
                isHeightValid = false;
            }
        }
        while (!isHeightValid);
    

    为什么:编译器不够聪明,无法确定while(condition) 的第一次迭代对于一般情况将始终执行,因此它假定while 中的代码可能无法运行,因此变量不会被分配。是的,在您的特定情况下,实际上可以检测到第一次迭代运行,但这可能不够常见,无法向编译器添加规则。

    do ... while 另一方面保证至少发生一次迭代,因此从编译器的角度来看,变量赋值(通过out 参数)总是会发生。

    【讨论】:

      【解决方案3】:
      public void heightAndWeight()
          {
              double height = getValue("What is your height in inches?",36,80);
              double weight = getValue("What is your weight in kilograms?",45,135);
              if (height > 0 && weight > 0)
              {
                  Console.WriteLine("your BMI is " + (height * weight).ToString("N2"));
              }
          }
          private double getValue(string question,int lowRange,int highRange) {
              double ret = 0;
              while(ret==0){
                  Console.WriteLine(question);
                  string retStr = Console.ReadLine();
                  if(double.TryParse(retStr,out ret))
                  {
                      if(ret<lowRange||ret>highRange){
                         Console.WriteLine("You must enter a value between "+lowRange.ToString()+" and "+highRange.ToString()+". Please try again.");
                         ret=0;
                       }else{
                          return ret;
                       }
                  }else{
                      Console.WriteLine("Invalid entry. Please try again");
                  }
              }
              return ret;
          }
      

      【讨论】:

      • 很好的重构。此外,我不建议使用 0 作为特殊的“未分配”值。问题中的原始代码最好用单独的布尔变量来表达。如果您想保留单个变量来保存值和“还没有值”,则可以使用可为空值。
      • 不需要额外的变量。当值有效时,只需使用while (true)return
      【解决方案4】:

      你为什么不想用一些初始化变量,例如,负值;在用户插入有效值之前,您的代码不会到达末尾

      【讨论】:

        【解决方案5】:

        满足您的请求会破坏本地范围的目的。不能有充分的理由这样做。在本地声明变量的目的是不要在更广泛的范围内乱扔垃圾。在您的情况下,这不是噪音,您的 userWidth 和 userHeight 变量在主范围内有意义,因为您在那里使用它们。因此,您要么在方法中正确初始化它们,要么在 if 中声明它们并将使用它们的代码也移动到 if 部分。后者意味着你有一些双重代码,你可以通过将 BMI 的计算移动到一个单独的方法并在两个 if 部分中调用它,将你的变量作为参数传递并取回 BMI 来解决这个问题。

        如果将计算和输出语句放在同一个方法中,那就不好了。但那是另一回事了。

        【讨论】:

          猜你喜欢
          • 2011-07-03
          • 2013-12-08
          • 1970-01-01
          • 2013-07-12
          • 2021-12-29
          • 2011-12-06
          • 1970-01-01
          • 2012-07-16
          • 1970-01-01
          相关资源
          最近更新 更多