Reputation: 8626
I'm learning C# via Rob Miles Yellow Book and have hit a problem with understanding variable scope.
The class I have developed (at the bottom) asks for a number and then displays it back to user. I would like to enhance it so that if the user enters ten instead of 10 it outputs a message and the user has another attempt.
Here is one of several attempts so far at the change...
...
static int readInt(string prompt, int low, int high)
{
int result;
do
{
try
{
string intString = readString(prompt);
result = int.Parse(intString);
Console.WriteLine("Thank you");
}
catch
{
Console.WriteLine("Invalid age value");
}
} while ((result < low) || (result > high));
return result;
}
...
Unfortunately this has the effect (I think) of pushing result
out of scope because with this change I see the following compliation error:
CS0165 Use of unassigned local variable 'result'
What is the C# way to achieve this?
The complete class:
using System;
class Exception1
{
static string readString(string prompt)
{
string result;
do
{
Console.Write(prompt);
result = Console.ReadLine();
} while (result == "");
return result;
}
static int readInt(string prompt, int low, int high)
{
int result;
do
{
string intString = readString(prompt);
result = int.Parse(intString);
} while ((result < low) || (result > high));
return result;
}
public static void Main()
{
const int SCORE_SIZE = 1;
int[] scores = new int[SCORE_SIZE];
for (int i = 0; i < SCORE_SIZE; i++)
{
scores[i] = readInt("Score : ", 0, 1000);
}
for (int i = 0; i < SCORE_SIZE; i++)
{
Console.WriteLine("Score " + i + " is " + scores[i]);
}
Console.Read();
}
}
Upvotes: 2
Views: 1525
Reputation: 6567
Just wanted to add possible solution if you really don't want to set result to any value initially:
static int readInt(string prompt, int low, int high)
{
bool validInput;
int result;
do
{
if ((validInput = int.TryParse(readString(prompt), out result)))
Console.WriteLine("Thank you");
else
Console.WriteLine("Invalid age value");
} while (!validInput || (result < low) || (result > high));
}
If TryParse
fails, result will be set to integer default value (0) and validInput
variable will be set to false so loop will go through once again.
Upvotes: 2
Reputation: 21661
In addition to Patrick Hoffman's answer, which is correct, you should look into using int.TryParse
instead of int.Parse
.
Using exception handling for flow control is generally a bad idea, and this is illustrative of one reason why. The compiler is recognizing that an exception could happen before result
is actually assigned (which is in fact the case if the user never enters a numeric value). It won't be able to evaluate the unassigend variable properly. If you use TryParse
, you won't have this particular issue.
Exception handling should only be used when you realize there are factors beyond your control or ability to handle well with regular code and checks (if (bTryParseReturn == false) ....
) - when user input might be so problematic that there's no straightforward way to test it, for example. Even then, the exception should generate an error, not just a "try again" situation - it's entirely possible that the exception can never really be recovered from or avoided, especially since you're catching all exceptions (and not just an InvalidCastException
or something like that). For example, imagine that the exception is a System.OutOfMemoryException
(the user tried to enter a terrabyte of data at your prompt). Your program will try to chug along merrily and horribly crash from the user's perspective.
Upvotes: 1
Reputation: 176
The compiler can't guarantee the property result is ever set yet still is expected to output result at the end of the method.
There could be an exception thrown or various other issues that prevent result being set prior to reaching the last line of the method.
So the compiler is pre-empting a NullReferenceException scenario and regards it as a compilation error.
It's doing you a favour :)
As previously stated, give the property result a default value to solve this issue.
If the property was at class level it would be implicitly set it's property type default value - but that's for another question.
Upvotes: 1
Reputation: 157048
The compiler doesn't know that the while
loop actually runs (it can throw and exception before assigning result
) and sets a value on result
. Therefore it complaints about this.
You can circumvent this by assigning a default value to result
:
int result = -1;
Or by setting a value in the catch
block:
catch
{
result = -1;
Console.WriteLine("Invalid age value");
}
I always use -1
in these cases as indicator of 'something wrong with this value'.
Upvotes: 6