As for your question (about the error). Basically, the variable is visible inside the blocks that you declare it in. if you declare it inside an if
block, then it will be visible only inside that if
block. if you declare it inside a class
block, it'll be visible inside that class and its methods, and also possible other classes if you use the correct access modifiers.
So, if you need to access a variable, you need to choose where to declare it based on its usage.
However, this is not the only issue you have. You're taking user input and using it directly. This is not the best practice. you'll need to validate the values before using them. Otherwise, you'll be dealing with a lot of exceptions that will be thrown on each point of your code, and the bigger the application the worse it'll get.
here is some points that will help you improve your code :
Validate user input before using it, this means you'll store the user input inside a temporary variable, then pass it into your validation logic, if passed the validation process, then assign its value to the original variable.
Model your application. C# is Object-Oriented-Programming language. It's easier to build a code structure that makes it easier to read, maintain, and expand. For instance, if your application depends on certain values (like gender, age, height, weight), why not creating a model that will store these values, and then you can pass this model on your code back and forth.
public class PersonInfo
{
public string Gender { get; set; }
public int Age { get; set; }
public int Height { get; set; }
public int Weight { get; set; }
public int ActivityLevel { get; set; }
public double Calories { get; set; }
}
With this, you'll always use this model in your code, and you'll know the values are store inside this model, which can make your work much easier.
Make use of Enum enum is there for a reason. It'll be useful to use it. in your case, you can use it for the type of input like this :
public enum InputType { Age, Height, Weight, ActivityLevel }
Don't convert the source values
You need to keep the source as is. If you need to display the values in different types such as from decimals to int. You can convert them at run-time, but don't touch the source. This is because you may need to re-use the source values somewhere else in the code. So, if you convert the source, it'll mess things up.
Use the proper methods sometimes, you'll hit a point where you'll need to use for instance loops, but for some reason you just skip that needs. This will probably causes some bugs and issues in the code logic. For instance, your application required age, height, weight, and activity level in order to calculate the calories. If one of them is missing, then the formula is wrong, and if the formula is wrong. if you only get the value onetime, and never go back if invalid, then there is no reason of using the formula at all, since the values are wrong. So, for this, you want to make sure you'll get each one of them before run the formula. Either you create a loop and keep tracking of user input, if invalid just force the user to input valid value. Or simply exit the application.
Code Reuse
Always code with the intention of reusing the same code even if you know it won't be reused anywhere else. This means, you'll take some parts of the code and place them in a position where it can be reused and maintained easily. An example of that, gender, you can put it in a method and recall it. Calories formula also can be used as method, and so on.
Finally, I put together a sample of these points to give more visual thoughts, and I hope it'll help.
// Person Information Model
public class PersonInfo
{
public string Gender { get; set; }
public int Age { get; set; }
public int Height { get; set; }
public int Weight { get; set; }
public int ActivityLevel { get; set; }
public double Calories { get; set; }
}
class Program
{
private static PersonInfo info = new PersonInfo();
public enum InputType { Age, Height, Weight, ActivityLevel }
static void Main(string[] args)
{
// default is null, to tell the application is invalid input
string _gender = null;
// keep the user inside this loop as long as the input is invalid.
while (_gender == null)
{
Console.WriteLine("Gender: Male(M)/Female(F)?");
_gender = GetGender(Console.ReadLine());
if (_gender == null)
Console.WriteLine("Gender has not been specified correctly. Please retype it.");
}
// it'll not go out of the loop until the user input is correct.
info.Gender = _gender;
// Create an array of inputs that you'll take from the user.
InputType[] inputs = { InputType.Age, InputType.Height, InputType.Weight, InputType.ActivityLevel };
bool hasError = false;
// Loop over the required inputs, and don't go to the next one until the user input a correct value.
for (int x = 0; x < inputs.Length; x++)
{
double userinput;
if (hasError)
x--;
if (inputs[x] != InputType.ActivityLevel)
{
Console.WriteLine("{0}? {1} ", inputs[x].ToString(), x);
userinput = GetInt(Console.ReadLine(), inputs[x]);
}
else
{
Console.WriteLine("How active are you?(Choose by inserting the number)");
Console.WriteLine("1.No exercise");
Console.WriteLine("2.Little to no exercise");
Console.WriteLine("3.Light exercise(1-3 days a week)");
Console.WriteLine("4.Moderate exercise(3-5 days a week");
Console.WriteLine("5.Heavy exercise(6-7days a week)");
// Console.WriteLine("6.Very heavy exercise(Twice per day, extra heavy workouts");
userinput = GetInt(Console.ReadLine(), InputType.ActivityLevel);
if (userinput >= 0 && userinput < 6)
{
info.ActivityLevel = (int)userinput;
info.Calories = GetCalories(info.Gender, info.Weight, info.Height, info.Age, info.ActivityLevel);
}
else
{
//reset input
userinput = -1;
Console.WriteLine("Please choose a number between 0 and 5");
}
}
if (userinput != -1)
{
SetValues((int)userinput, inputs[x]);
hasError = false;
}
else
{
Console.WriteLine("{0} has not been specified correctly. Please retype it.", inputs[x].ToString());
hasError = true;
}
}
// Now, you can show the user info with the calories as well.
Console.WriteLine("Your Gender\t\t:\t{0}", info.Gender);
Console.WriteLine("Your Age\t\t:\t{0}", info.Age);
Console.WriteLine("Your Height\t\t:\t{0}", info.Height);
Console.WriteLine("Your Weight\t\t:\t{0}", info.Weight);
Console.WriteLine("Your Activity Level\t:\t{0}", info.ActivityLevel);
Console.WriteLine("Your daily calories\t:\t{0} kcal", Math.Round(info.Calories));
Console.ReadLine();
}
public static string GetGender(string input)
{
if (!string.IsNullOrEmpty(input))
{
switch (input.ToLower())
{
case "m":
case "male":
return "m";
case "f":
case "female":
return "f";
default:
return null;
}
}
else
{
return null;
}
}
public static double GetActivityLevel(int level)
{
switch (level)
{
case 0:
return 1;
case 1:
return 1.2;
case 2:
return 1.375;
case 3:
return 1.55;
case 4:
return 1.725;
case 5:
return 1.9;
default:
return -1;
}
}
public static int GetInt(string input, InputType type)
{
if (!string.IsNullOrEmpty(input))
{
if (int.TryParse(input, out int result))
{
return result;
}
else
{
return -1;
}
}
else
{
Console.WriteLine(type.ToString() + " is empty");
return -1;
}
}
public static void SetValues(int input, InputType type)
{
switch (type)
{
case InputType.Age:
info.Age = input;
break;
case InputType.Weight:
info.Weight = input;
break;
case InputType.Height:
info.Height = input;
break;
}
}
public static double GetCalories(string gender, int weight, int height, int age, int activityLevel)
{
if (string.IsNullOrEmpty(gender))
{
Console.WriteLine("Gender has not been specified");
return -1;
}
else
{
double _cal;
var _level = GetActivityLevel(activityLevel);
if (gender == "m")
_cal = (66.4730 + (13.7516 * weight) + (5.0033 * height) - (6.7550 * age));
else
_cal = (655.0955 + (9.5634 * weight) + (1.8496 * height) - (4.6756 * age));
//check first Activity Level, if is it -1 then it's invalid input, those it'll return it.
return _level != -1 ? _cal * _level : -1;
}
}