如何在c#中引用作用域外的变量

本文关键字:作用域 变量 引用 | 更新日期: 2023-09-27 18:04:56

教授让我们编写一个程序,输入用户的身高和体重,然后计算bmi。我决定更进一步,添加一些"输入验证"逻辑。这意味着,如果有人输入"cat"作为他们的体重,它会让用户知道"cat"不是有效的体重。

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#中引用作用域外的变量

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

你可以尝试用一个默认的有效值来初始化它们:

float userHeight = DEFAULT_HEIGHT;
float userWeight = DEFAULT_WEIGHT;

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参数)总是会发生。

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;
    }

为什么不初始化一些变量,例如,负值;除非用户插入有效值,否则代码不会结束

满足您的请求将破坏局部作用域的目的。这样做没有充分的理由。局部声明变量的目的是不让更广泛的作用域受到干扰。在您的情况下,它不是噪音,您的userWidth和userHeight变量在主作用域中有意义,因为您在那里使用它们。你要么在方法中初始化它们要么在if中声明它们并将使用它们的代码也移到if部分中。后者意味着您有一些双重代码,您可以通过将BMI的计算移动到一个单独的方法中并从两个if部分中调用该方法,将变量作为参数传递并返回BMI来解决这个问题。

将计算和输出语句放在同一个方法中并不好。但那是另一个故事了