How to reference a variable outside of scope in C# - c#

My professor asked us to create a program that takes in a user's height and weight, and then calculate bmi. I decided to take it a little further and added in some "input validation" logic. This means that if someone inputs "cat" for their weight, it let the user know that "cat" is not a valid weight.
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);
}
}
The error I get is "use of unassigned local variable..". I know that I am assigning the user variables within IF statements, and that they only persist until the end of that IF statement.
My question is, how do I assign a variable in an if statement, and then reference the new value of that variable outside of that statement?
Certainly I don't have to nest them all, because that seems tedious....

The issue here is that there is a chance that your variables userHeight and userWeight are still holding garbage value since you did not initialize them.
You can try initializing them with a default valid:
float userHeight = DEFAULT_HEIGHT;
float userWeight = DEFAULT_WEIGHT;

Do ... while(condition) is more suitable for your case and also allows compiler to confirm that value is actually assigned:
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);
Why: compiler is not smart enough to figure out that first iteration of while(condition) for general case will be always executed, so it assumes that code inside while may not run and hence variables will not be assigner. Yes, in your particular case it actually possible to detect that first iteration runs, but likely this is not common enough case to add rule to compiler.
do ... while on other hand guarantees that at least one iteration happens and hence variable assignment (via out parameter) will always happen from compiler's point of view.

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

Why don't you want to initialize the variables with some, for example, negative value; Your code is not going to reach the end until valid values are inserted by user anyway

Fulfilling your request would defeat the purpose of local scope. It cannot be done for good reason. The point of declaring a variable locally is to not litter the broader scope with noise. In your case it isn't noise, your userWidth and userHeight variables have meaning in the main scope because you use them there. So you either initialize them properly up in the method or you declare them inside the if and move the code that uses them into the if section as well. The latter would mean you have some double code, you can fix that by moving the calculation of the BMI to a separate method and call that from within both if sections, passing your variables as arguments and getting back the BMI.
It would not be nice to put the calculation and the output statement in the same method. But that's another story.

Related

Why does this code not work when I try to convert it

This is only a small piece of the code I'm trying to make work. The original code I wrote works but I want to make sure when the user inputs a number it is in fact a number.
Console.WriteLine("Give the number of A");
A =Convert.ToDouble( Console.ReadLine());
if (char.IsNumber(Convert.ToDouble(A)) == correct)
{
Console.WriteLine(Convert.ToDouble( A * A));
}
else
{
Console.WriteLine("Incorrecrt input");
}
The Console.WriteLine(Convert.ToDouble(A*A)); I only wrote to see if that will work and it doesn't. After the user inputs only a number I must use it in another equation for a final answer. The user must input 3 numbers.
For me, you should check is the input is a number that you can convert to double before converting it.
Console.WriteLine("Give the number of A");
var a = Console.ReadLine();
double number;
if (double.TryParse(a, out number))//double.TryParse takes a parameter and tries to convert it to double. If the convertion is successfull, sets the out parameter as result and returns true. If not, returns false. And you can use with other types like int.Tryparse(param, out outParam);
{
A = number;
}
else
{
//Not a number, show a message etc...
{
If you break this down:
A =Convert.ToDouble( Console.ReadLine());
if (char.IsNumber(Convert.ToDouble(A)) == correct)
{
}
What you're basically doing is:
Double A = Convert.ToDouble(Console.ReadLine());
Double dbl = Convert.ToDouble(A);
Boolean bl = char.IsNumber(dbl);
if (bl== correct)
{
}
So there's multiple things wrong here.
Firstly, you're trying to convert the user input without any sort of guarantee of success, so if someone typed "A" instead of a number it will throw an exception.
You should use TryParse and then if it's a valid conversion proceed.
Secondly, you're checking if a Double is a char that can be converted to a number. Obviously not because it's already a Double.
Thirdly, you're checking if a Boolean is equal to some variable called correct (which you haven't provided the definition of) so it's not clear if this is a valid comparsion.
EDIT:
This is what I would do:
bool validInput = false;
do
{
Console.WriteLine("Give the number of A");
string userInput = Console.ReadLine();
if (double.TryParse(userInput, out double result))
{
validInput = true;
Console.WriteLine(result * result);
Console.ReadLine();
}
else
{
Console.WriteLine("Invalid input. Please type a number.");
}
} while (!validInput);

C# Method Declaring

public void GetPosNonZeroDouble()
{
double x;
Console.WriteLine("Enter The Length Of The Side");
x = double.Parse(Console.ReadLine());
if (x <= 0)
Console.WriteLine("Error - input must be a non - zero positive number");
else
return x;
x = double.Parse(Console.ReadLine());
}
static void ProcessSquare()
{
GetPosNonZeroDouble();
double side;
double answer;
Console.WriteLine();
side = double.Parse(Console.ReadLine());
answer = Math.Pow(side, 2);
Console.WriteLine("The Square Area is {0}", answer);
}
I am supposed to have a "GetPosNonZeroDouble" which needs to act like this image: c#Question
I have declared this method but am unsure how I tell processSquare() to check if the number is < 0 and how to display such by inputing the module.
Please assist me with this as i am stuck finding the solution to my problem.
You need to either make the method static, or make it part of a class and call it from an instance of the class. Also, you can't return values from a void method.
public static double GetPosNonZeroDouble()
{
double x = 0;
while (x <= 0)
{
Console.WriteLine("Enter The Length Of The Side");
if (!double.TryParse(Console.ReadLine(), x) || x <= 0)
{
Console.WriteLine("Error - input must be a non - zero positive number");
}
}
return x;
}
GetPosNonZeroDouble
Is an instance method that you are trying to call from a static method and you can't do that. You need to create an instance of whatever class GetPosNonZeroDouble is in and then invoke it using the dot notation.
Have a look here and you should also try some C# tutorials to get you going.
It seems that you don't have experience with methods in general.
As a start, I would recommend you to check the official C# documentation for methods:
https://msdn.microsoft.com/en-us/library/vstudio/ms173114(v=vs.100).aspx
For example, your method GetPosNonZeroDouble() does not return anything but you try to return a value with return x; (which would end up in a compiler error).

Out Parameters Questions [duplicate]

This question already has answers here:
Error : The Out Parameter must be assigned before control leaves the current method
(2 answers)
Closed 8 years ago.
Went to check this program I've been doing and I seem to of hit another road back with the error saying; The out parameter 'checkedIfInsured' must be assigned to before control leave the current method.
I can paste the rest of the code if necessary but to me looking at it, it looks fine.
static void GetData(out int patientsID, out string patientsName, out int patientsAge, out decimal patientsAmount, object o, out char checkedIfInsured)
{
string inString;
int count = 3;
char test;
Console.Write("Please enter Patients ID number>> ");
inString = Console.ReadLine();
int.TryParse(inString, out patientsID);
Console.Write("Please Enter Name for " + "Patient {0} >> ", patientsID);
patientsName = Console.ReadLine();
Console.Write("Please Enter The Age For " + "Patient {0}>> ", patientsName);
inString = Console.ReadLine();
int.TryParse(inString, out patientsAge);
Console.Write("Please Enter The Amount Due For " + "Patient {0}>> ", patientsID);
inString = Console.ReadLine();
decimal.TryParse(inString, out patientsAmount);
Console.WriteLine("-----------------------------------");
if (o is InsuredPatient)
{
Console.WriteLine(" Enter the name of the Patients Insurance Company Code>>");
for (int x = 0; x < count; ++x)
Console.WriteLine("{0,-3} = {1,5}", InsuredPatient.InsurerCharacter[x], InsuredPatient.InsurerName[x]);
Console.WriteLine(" Enter talent code >> ");
test = Console.ReadKey().KeyChar;
for (int i = 0; i < InsuredPatient.InsurerCharacter[i]; ++i)
if (test == InsuredPatient.InsurerCharacter[i])
{
checkedIfInsured = InsuredPatient.InsurerCharacter[i];
}
}
}
If the if is not true, you still need to assign a value in the else. All branches of the code must return a value.
if (o is InsuredPatient)
{//...}
else{
//default to whatever.
checkedIfInsured = myDefaultInsuredCheckedValue;
}
You're only assigning the checkIfInsured parameter if o is InsuredPatient. The compiler is telling you that it needs to always be assigned to.
You only give checkedIfInsured a value in one particular conditional branch. The compiler is telling you that you must give it a value before the method ends, regardless of what conditional branch it takes.
You can avoid this error by setting checkedIfInsured to a default value at the beginning of your method.
checkedIfInsured may not always have a value as it is inside an if block. What if the criteria of the if is not met?
The compiler is complaining because there exists a code path where checkedIfInsured hasn't been set, namely the case where the test variable does not equal InsuredPatient.InsurerCharacter[i].
What you could do is set checkedIfInsured to some default character at the beginning of the method to handle the case that test does not equal InsuredPatient.InsurerCharacter[i].
You are only assigning 'checkedIfInsured' inside an 'if' block. If the condition doesn't hold, it won't get assigned, and that is what the compiler is complaining about.
Make sure you assign 'checkedIfInsured' outside the 'if' block.

Making a program do absolutely nothing when certain data or wrong answer is put in

I have this crazy idea, I would like a program to not execute anything if the wrong data is put into the console. Such as the alphabet, weird characters. All I want is decimal numbers and a period to be accepted. If the wrong data is typed in, I want the program to STAY there and do absolutely nothing after you hit enter.
My mindset thinks:
if (sum != decimal)
{
// Don't do anything, just leave it as is.
code I have no clue about.
}
Now, you must be thinking, you can't use datatypes for an if statement! Maybe you can, but its not working for me. I'm sorry I'm a big noob.
try
{
Console.WriteLine("Put in the price of the product");
string input = Console.ReadLine();
decimal sum = Convert.ToDecimal(input);
if (sum <= 100)
{
decimal totalprice = sum * .90m;
Console.WriteLine("Your final price is {0:0:00}", totalprice);
}
}
catch
{
}
I was also thinking maybe a try and catch statement would work too, but again, I have no clue what to put in that either.
If your answers could be noob-safe and explained. (Because I want to learn the concept of how this stuff works) that would be nice.
A visual example:
When you hit enter, nothing happens but when you put in the correct datatype, the program will continue.
Datatypes are not written to console. Only strings could be retrieved from console input. What type has string "2" - decimal, int, byte, string? All you can do is try to parse some type from your input string:
Int32.TryParse("2", out value)
For your case:
Console.WriteLine("Put in the price of the product");
string input = Console.ReadLine();
decimal sum;
if (!Decimal.TryParse(input, out sum))
{
Console.WriteLine("Decimal number cannot be parsed from your input.");
return;
}
if (sum <= 100)
Console.WriteLine("Your final price is {0:0:00}", sum * 0.90M);
UPDATE
Decimal.TryParse - Converts the string representation of a number to its Decimal equivalent. A return value indicates whether the conversion succeeded or failed. It does not throws an exception if conversion failed.
! Operator - it is NOT operator. The logical negation operator (!) is a unary operator that negates its operand. It is defined for bool and returns true if and only if its operand is false.
So if (!Decimal.TryParse(input, out sum)) verifies if conversion was NOT successful. Then I put a sample message for user and exited from method (if it was your Main method, then program will terminate. But this all is out of your initial question about parsing strings.
Try this (note the while/break pairing):
while (true)
{
string input = Console.ReadLine();
decimal sum;
if (Decimal.TryParse(input, out sum) == true)
{
if (sum <= 100)
{
decimal totalprice = sum * .90m;
Console.WriteLine("Your final price is {0:0:00}", totalprice);
break; // break out of while
}
}
}
The conversion function you are using will I believe throw an exception if it cannot convert the string passed to the requested type. Generally, exceptions should be avoided for controlling program flow, and reserved for truly unexpected situations. Instead, you should look to using a method that doesn't throw an exception, but instead returns a value to indicate success or failure. With this in ind you could try:
try
{
Console.WriteLine("Put in the price of the product");
decimal sum;
// Repeat forever (we'll break the loop once the user enters acceptable data)
while (true)
{
string input = Console.ReadLine();
// Try to parse the input, if it succeeds, TryParse returns true, and we'll exit the loop to process the data.
// Otherwise we'll loop to fetch another line of input and try again
if (decimal.TryParse(input, out sum)) break;
}
if (sum <= 100)
{
decimal totalprice = sum * .90m;
Console.WriteLine("Your final price is {0:0:00}", totalprice);
}
}
catch
{
}

C# How to loop user input until the datatype of the input is correct?

How to make this piece of code loop asking for input from the user until int.TryParse()
is successful?
//setX
public void setX()
{
//take the input from the user
string temp;
int temp2;
System.Console.WriteLine("Enter a value for X:");
temp = System.Console.ReadLine();
if (int.TryParse(temp, out temp2))
x = temp2;
else
System.Console.WriteLine("You must enter an integer type value"); 'need to make it ask user for another input if first one was of invalid type'
}
Version of the code after the helpful answer:
//setX
public void setX()
{
//take the input from the user
string temp;
int temp2;
System.Console.WriteLine("Enter a value for X:");
temp = System.Console.ReadLine();
if (int.TryParse(temp, out temp2))
x = temp2;
else
{
Console.WriteLine("The value must be of integer type");
while (!int.TryParse(Console.ReadLine(), out temp2))
Console.WriteLine("The value must be of integer type");
x = temp2;
}
}
while (!int.TryParse(Console.ReadLine(), out mynum))
Console.WriteLine("Try again");
edit:
public void setX() {
Console.Write("Enter a value for X (int): ");
while (!int.TryParse(Console.ReadLine(), out x))
Console.Write("The value must be of integer type, try again: ");
}
Try this. I personally prefer to use while, but do .. while is also valid solution. The thing is that I don't really want to print error message before any input. However while has also problem with more complicated input that can't be pushed into one line. It really depends on what exactly you need. In some cases I'd even recommend to use goto even tho some people would probably track me down and slap me with a fish because of it.
Even though the question has been already marked as answered, do-while loops are much better for validating user input.
Notice your code:
Console.WriteLine("The value must be of integer type");
while (!int.TryParse(Console.ReadLine(), out temp2))
Console.WriteLine("The value must be of integer type");
You have the same code at top and bottom. This can be changed:
do {
Console.WriteLine("The value must be of integer type");
} while (!int.TryParse(Console.ReadLine(), out temp2));
This can help too
public int fun()
{
int Choice=0;
try
{
Choice = int.Parse(Console.ReadLine());
return choice;
}
catch (Exception)
{
return fun();
}
}
I've been wondering quite a lot, but I just figured it out!
int number;
bool check;
do
{
Console.WriteLine("Enter an integer:");
check = int.TryParse(Console.ReadLine(), out num1);
}
while (!check);
This code will loop until the user has entered an integer number. This way, the program doesn't simply report an error, but instead immediately allows the user to input again another, correct value.

Categories