im working on a assignment where I now have to implement the Try & Catch-method too catch inputs other than numbers in my program. I understand the process and explanations in my study-book and have also done some minor examples while trying it out. But when I want to implement this into my assignment I am getting stuck. Can someone please explain to me in a manor as to not spoil anything but try and help me along the way?
Here is my code:
using System;
namespace BastunKP
{
class Program
{
public static double FahrToCels(double fahr)
{
return (fahr - 32) * 5 / 9;
}
public static void Main(string[] args)
{
Console.WriteLine("Skriv in Fahrenheit: ");
double fahr = Convert.ToDouble(Console.ReadLine());
double tempCels = FahrToCels(fahr);
do
{
try
{
//Dont know what to write here.
}
catch
{
Console.WriteLine("Du kan bara skriva in siffor, testa igen.");
}
if (tempCels < 73)
{
Console.WriteLine("Temperaturen är för kallt, skruva upp lite!");
}
else if (tempCels > 77)
{
Console.WriteLine("Temperaturen är för varmt, skruva ner lite!");
}
else
{
Console.WriteLine("Temperaturen är nu bra, hoppa in!");
Console.ReadKey();
}
fahr = Convert.ToDouble(Console.ReadLine());
tempCels = FahrToCels(fahr);
}
while (tempCels < 73 || tempCels > 77);
return;
}
}
}
First of all, lets write code without any exception handling. Get the basics right first. We need a method that:
Asks the user for a temperature in Fahrenheit.
If the input is not a valid double, go to 1.
Convert the value to Celsius.
If not, go to 1.
If the temperature in Celsius does not belong to (73, 77) go to 1.
public static double GetTemperatureFromUser()
{
while (true)
{
Console.Write("Enter temperature in Fahrenheit: ");
var t = FahrToCels(Convert.ToDouble(Console.ReadLine()));
if (t < 73)
{
Console.Write("Temperature is too low. Try again.");
}
else if (t > 77)
{
Console.Write("Temperature is too high. Try again.");
}
else
{
return t;
}
}
}
Ok, that looks good. Now let's add some exception handling. First question: what can go wrong here and throw an exception?
var t = FahrToCels(Convert.ToDouble(Console.ReadLine()));
seems like a likely suspect. Is there anything else that can throw? Hmmm, no.
Ok, second question: what code shouldn't be executing if ToDouble() throws? Well, anything that depends on the result of ToDouble() obviously. So all that code also goes in the try block.
Ok, third question: what code should run if ToDouble() throws? In our case we should inform the user that the input was not a valid double. Ok, that code needs to go in catch block.
Think of try-catch as a fancy if that controls the execution path of your code: if the code throws, go to catch if not, keep executing normally inside the try block.
Fourth question: what code should run after everything else inside the try or catch blocks no matter what happens? In your case nothing, but if there were, it would go in the finally block.
Note that catch and finally blocks are not mandatory. The only rule is that at least one of them must be present immediately following a try block; try-catch, try-finally and try-catch-finally are all valid.
Fifth and last: what exceptions do you want to handle? You should always handle only the exceptions that you know how to handle and ignore all others. What exceptions can ToDouble throw? If you read the documentation you'll see it can throw FormatException and OverflowException. You can handle both because they amount to the same thing: and invalid user input.
Ok, lets rewrite our method:
Does the while loop depend on whatever happens in ToDouble? No, the method should be running in a loop no matter what happens inside; the only way to exit the loop is when the user inputs a valid number and the method returns. Ok then, the while block goes outside any exception handling and so does the user prompt:
public static double GetTemperatureFromUser()
{
while (true)
{
Console.Write("Enter temperature in Fahrenheit: ");
//...
}
}
And now the next instruction is our primary suspect, so it obviously must go inside the try block. Everything else we've written in our method depends on the value of t so we put all that also inside the try block:
public static double GetTemperatureFromUser()
{
while (true)
{
Console.Write("Enter temperature in Fahrenheit: ");
try
{
var t = FahrToCels(Convert.ToDouble(Console.ReadLine()));
if (t < 73)
{
Console.Write("Temperature is too low. Try again.");
}
else if (t > 77)
{
Console.Write("Temperature is too high. Try again.");
}
else
{
return t;
}
}
}
}
Ok, now we're only missing the catch block. We'll add one for each exception we know how to handle:
public static double GetTemperatureFromUser()
{
while (true)
{
Console.Write("Enter temperature in Fahrenheit: ");
try
{
var t = FahrToCels(Convert.ToDouble(Console.ReadLine()));
if (t < 73)
{
Console.Write("Temperature is too low. Try again.");
}
else if (t > 77)
{
Console.Write("Temperature is too high. Try again.");
}
else
{
return t;
}
}
catch (FormatException)
{
Console.Write("Invalid number format. Try again.");
}
catch (OverflowException)
{
Console.Write("Number is too large or too small. Try again.");
}
}
}
And there you go, we're done.
There is no required try/catch to check valid input. You could use double.TryParse;
Console.WriteLine("Skriv in Fahrenheit: ");
double fahr;
double tempCels;
bool isInputCorrect = false;
while (!isInputCorrect)
{
var input = Console.ReadLine();
if (!double.TryParse(input, out fahr))
{
Console.WriteLine("Du kan bara skriva in siffor, testa igen.");
continue;
}
tempCels = FahrToCels(fahr);
if (tempCels < 73)
{
Console.WriteLine("Temperaturen är för kallt, skruva upp lite!");
continue;
}
else if (tempCels > 77)
{
Console.WriteLine("Temperaturen är för varmt, skruva ner lite!");
continue;
}
isInputCorrect = true;
}
Console.WriteLine("Temperaturen är nu bra, hoppa in! tempCels : " + tempCels);
Console.ReadKey();
If you insist to use try/catch, you could try like this;
Just replace double.TryParse part.
var input = Console.ReadLine();
try
{
fahr = Convert.ToDouble(input);
}
catch (Exception e)
{
Console.WriteLine("Du kan bara skriva in siffor, testa igen.");
continue;
}
Related
I'm a beginner in C# and I'd like to know if there a better way to write this 3+3 math problem by using loops, like maybe a do while loop ?
My code is the following :
static void Main (string[] args) {
Console.WriteLine ("What is 3+3?");
int answer = int.Parse (Console.ReadLine ());
int counter = 1;
if (answer == 6) {
Console.WriteLine ("Great! thats Correct! you've got it in the first try");
} else {
while (answer != 6) {
Console.WriteLine (" Wrong, please try again");
answer = int.Parse (Console.ReadLine ());
counter++;
if (answer == 6) {
Console.WriteLine ("Correct! Well done! you got it in {0} tries", counter);
}
}
}
Console.ReadLine ();
}
The aim of this program is to ask the user a question, check the answer and output a statement that says how many tries the user took to get the answer right.
If you could provide me suggestions.
If you're just wanting less code / a more concise option you could go for either of the following.
Note I've ignored the use of a slightly different error message for the first case and other cases. If this is important then you can of course have an if (counter == 1) statement.
This first example uses Do/While which will always execute the loop at least once and then check the exit condition (answer == 6) at the end of every loop.
static void Main(string[] args)
{
Console.WriteLine("What is 3+3?");
int answer;
int counter = 0;
do
{
answer = int.Parse(Console.ReadLine());
counter++;
if (answer == 6)
{
Console.WriteLine("Correct! Well done! you got it in {0} tries", counter);
}
else
{
Console.WriteLine(" Wrong, please try again");
}
}
while (answer != 6);
Console.ReadLine();
}
This second example uses a while loop that loops forever and the break keyword which breaks out of a loop once a certain condition is met. This prevents the need for extra if statements to get rid of pesky extra messages etc.
static void Main(string[] args)
{
Console.WriteLine("What is 3+3?");
int answer;
int counter = 0;
while (true)
{
answer = int.Parse(Console.ReadLine());
counter++;
if (answer == 6)
{
Console.WriteLine("Correct! Well done! you got it in {0} tries", counter);
break;
}
Console.WriteLine(" Wrong, please try again");
}
Console.ReadLine();
}
I don't know very much about this, but at least, in C++, when you fail, I invoked again the main method with Main();, adding the error message.
Hope this solves your problem.
Using do/while will be significantly shorter:
static void Main(string[] args)
{
int counter = 1;
boolean hasAnswer = false;
do {
Console.WriteLine("What is 3+3?");
int answer = int.Parse(Console.ReadLine());
if (answer == 6)
{
Console.WriteLine("Great! thats Correct! You've got it in " + counter + " attempt(s)");
hasAnswer = true
}
else
{
Console.WriteLine(" Wrong, please try again");
counter++;
}
} while(!hasAnswer);
}
I haven't rewritten C# in a while so the syntax might be off, but that is the gist of how to do it.
This is homework, so I'm just looking for some guidance. I have my code working to return a value in an array[10] based on an index value given by the user.
What isn't working is that I need to stop the program when "99" is entered, a value that also triggers the try-catch IndexOutOfRangeException. I can't get the program to recognize the difference between "99" and any other out of range value. I did try it with an if-else, but "99" still threw the IndexOutOfRangeException and it wouldn't loop. An attempt at do-while also didn't work.
Code is below. Thanks in advance.
using System;
using static System.Console;
class SubscriptExceptionTest
{
static void Main()
{
double[] array = {20.3, 44.6, 32.5, 46.7, 89.6, 67.5, 12.3, 14.6, 22.1, 13.6};
int i = 0;
while (i != 99)
try
{
Write("Enter a number to see the value in that position. Type 99 to stop: ");
i = Convert.ToInt32(ReadLine());
double arrayVal = array[i];
WriteLine("The value at index {0} is {1}", i, arrayVal);
ReadLine();
}
catch (FormatException fe)
{
throw new FormatException("You did not enter an integer.");
}
catch (IndexOutOfRangeException ie)
{
throw new IndexOutOfRangeException("Index was outside the bounds of the array.");
}
catch (Exception ex)
{
throw new Exception("Error: " + ex.Message);
}
}
}
The problem is once you are catching IndexOutOfRangeException you are again throwing it inside the catch block which is not handled anywhere in the code.
The other problem is that you are not checking for the value of i for 99 before using it for accessing it in the array which leads to Exception.
See below -
int i = 0;
while (i != 99)
try
{
Write("Enter a number to see the value in that position. Type 99 to stop: ");
i = Convert.ToInt32(ReadLine());
if(i == 99) {
Console.WriteLine("Thanks!!, Breaking here!!!");
break;
}
double arrayVal = array[i];
WriteLine("The value at index {0} is {1}", i, arrayVal);
ReadLine();
}
catch (FormatException fe)
{
throw new FormatException("You did not enter an integer.");
}
catch (IndexOutOfRangeException ie)
{
// Show some message here
}
}
Put an if construct to check for value 99 and exit the application if the condition is true.
i = Convert.ToInt32(ReadLine());
if( i == 99 )
{
//Perform any operation you want to before exiting the application.
Console.WriteLine("Exiting Application");
//This will terminate the program.
Environment.Exit(0);
}
As a rule, Try/Catch's and Exception Handlers should only be used Exceptionally. They are expensive. Let me show you how to handle these issues using defensive programming.
I think using the Array.Length to check the Array Bounds if any other out of range value is the answer you want.
static void Main()
{
double[] array = {20.3, 44.6, 32.5, 46.7, 89.6,67.5, 12.3, 14.6, 22.1, 13.6};
int i = 0;
while (i != 99)
{
Write("Enter a number to see the value in that position. Type 99 to stop: ");
var result = ReadLine();
bool isInteger = int.TryParse(result, out i);
if (isInteger == false) throw new FormatException("You did not enter an integer.");
if (i == 99) Environment.Exit(0);
if (i < 0 || i > array.Length) throw new IndexOutOfRangeException("Index was outside the bounds of the array.");
double arrayVal = array[i];
WriteLine("The value at index {0} is {1}", i, arrayVal);
ReadLine();
}
So I recently started my first coding course for C#. I am currently trying to write a short program that prints out Yay! as many times as I indicate. Now to prevent any format exceptions, I've tried to add a try and catch to it. But, for some reason this isn't working and I can't seem to figure out why. The code is below:
Console.Write("Enter the number of times to print \"Yay!\": ");
string entry = Console.ReadLine();
var number = int.Parse (entry);
bool print = true;
while(print)
{
try
{
if(number <= 0)
{
print = false;
}
else
{
Console.WriteLine("Yay!");
number -= 1;
}
}
catch(FormatException)
{
Console.WriteLine("You must enter a whole number.");
}
}
Now to my knowledge, I have everything I need to make this work. Can anyone see where I went wrong with this?
Thanks a lot for reading!
It's
var number = int.Parse (entry);
that should throw the exception, and since it's beyond try {} scope, the
exception has not been caught. Move the fragment into the scope:
Console.Write("Enter the number of times to print \"Yay!\": ");
string entry = Console.ReadLine();
bool print = true;
try {
// int.Parse is within the try {} scope now
var number = int.Parse (entry);
while(print) {
...
}
}
catch(FormatException) {
Console.WriteLine("You must enter a whole number.");
}
Or convert int.Parse into int.TryParse and drop try {...} catch {...} at all (a better solution)
Console.Write("Enter the number of times to print \"Yay!\": ");
int number;
if (!int.TryParse(Console.ReadLine(), out number)) {
Console.WriteLine("You must enter a whole number.");
return;
}
bool print = true;
// There's no need in try {} catch {} now
while(print) {
...
}
You need to place your int.Parse inside your try-catch block.
Here's a revised version of your code.
static void Main(string[] args)
{
bool print = true;
while (print)
{
Console.Write("Enter the number of times to print \"Yay!\": ");
string entry = Console.ReadLine();
try
{
var number = int.Parse(entry);
for (int i = 0; i < number; i++)
{
Console.WriteLine("Yay!");
}
}
catch (FormatException)
{
Console.WriteLine("You must enter a whole number.");
}
}
}
I've read that using "goto" in C# is not recommended
However, my code uses goto and so far, errors appeared when trying to avoid "goto"
anum1r:
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
goto anum1r;
}
anum2r:
Console.Write ("What is the second number? ");
try {
num2 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
goto anum2r;
}
answer = num1 + num2;
How do I transform this code without using GOTO. ty
Use a while loop:
double num1;
while (true) {
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
break;
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
}
As you need this code twice, it is also a good idea to refactor it in a separate method like #James' answer. (Though it needs an extra parameter to modify the user prompt.)
You could use a while loop
private double? GetNumber()
{
double? result = null;
try {
result = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
return result;
}
...
// prompt for first number
double? num1 = null;
while (!num1.HasValue)
{
Console.Write ("What is the first number? ");
num1 = GetNumber();
}
// prompt for second number
double? num2 = null;
while (!num2.HasValue)
{
Console.Write ("What is the second number? ");
num2 = GetNumber();
}
// calculate result
answer = num1.Value + num2.Value;
There are two good ways to improve your code:
Extract into a separate method the logic for repeatedly asking the user for a number until they enter a valid one. (Use a loop construct to handle looping rather than a goto.)
Use double.TryParse() to avoid having to catch a format exception.
If you put both of those together, you get code that looks something like this:
using System;
namespace Demo
{
public static class Program
{
private static void Main()
{
double first = askForNumber("What is the first number? ");
Console.WriteLine();
double second = askForNumber("What is the second number? ");
Console.WriteLine("\nYou entered {0} and {1}", first, second);
}
private static double askForNumber(string prompt)
{
while (true)
{
Console.Write(prompt);
double result;
if (double.TryParse(Console.ReadLine(), out result))
return result;
Console.Beep();
Console.WriteLine("\nYou have entered an invalid number!\n");
}
}
}
}
You can use a for-loop and a collection like a double[], also use double.TryParse:
int numbers = 10;
double[] allNumbers = new double[numbers];
for (int i = 0; i < numbers; i++)
{
Console.Write("What is the {0}. number? ", i + 1);
double num;
if (double.TryParse(Console.ReadLine().Trim(), out num))
{
allNumbers[i] = num;
}
else
{
i--; // ask the user until we have the numbers
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
}
double answer = allNumbers.Sum(); // LINQ so add using System.Linq;
Another way is to extract a method for this purpose:
private static double? ReadNumberFromConsole()
{
double num;
if (double.TryParse(Console.ReadLine().Trim(), out num))
return num;
else
return null;
}
That makes the code more readable:
for (int i = 0; i < numbers; i++)
{
Console.Write("What is the {0}. number? ", i + 1);
double? num = ReadNumberFromConsole();
if (num.HasValue)
{
allNumbers[i] = num.Value;
}
else
{
i--; // ask the user until we have the numbers
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
}
I would also highly recommend avoid using Convert.ToDouble on user input.
Using exceptions as an input validating system is wrong on every level.
Use something like this instead:
double GetNumberFromUser() {
double Num = double.NaN;
while(!double.tryParse(Console.ReadLine(), out Num) && !double.IsNaN(Num))
{
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
return Num;
}
why test for IsNaN also? read this.
You MAY simply use a loop:
double PromptForNumber(string message) {
while (true) {
Console.Write(message + " ");
try {
return Convert.ToDouble(Console.ReadLine());
} catch (FormatException) {
Console.Beep();
Console.WriteLine();
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine();
}
}
}
Used as:
double num1 = PromptForNumber("What is the first number?");
double num2 = PromptForNumber("What is the second number?");
BUT here you're also using exceptions where they're not necessary. Invalid user input is not exceptional and there are better ways to handle that:
double PromptForNumber(string message) {
while (true) {
Console.Write(message + " ");
double number;
if (Double.TryParse(Console.ReadLine(), out number))
return number;
Console.Beep();
Console.WriteLine("\nYou have entered an invalid number!\n");
}
}
Note that this way you'll also handle OverflowException that you left out in your original code.
Do you need 100 inputs? One line of code:
var inputs = Enumerable.Range(1, 100)
.Select(x => PromptForNumber(String.Format("Enter number #{0}:", x)));
private Double InputNum1
{
Console.Write ("What is the first number? ");
try
{
num1 = Convert.ToDouble (Console.ReadLine ());
return num1;
}
catch (System.FormatException)
{
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
InputNum1();
}
}
you can use a while to query for numbers until they are valid:
double? num1 = null;
while (num1==null){
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
}
I'm making a program that has little programs inside of it, and I've come to a dilemma. On my first mini-program which rearranges digits to find the greatest possible number from those digits, it asks if the user wants to quit. If they respond "Yes" then the function returns 0 which is evaluated in the main(string[] args) method. My problem is that whenever the user says "No", the mini-program still doesn't continue. Here's my source:
namespace ACSL_Competition
{
class Program
{
static int DigitRearranger()
{
string[] mainString = {};
Console.WriteLine("---------Welcome to the Digit Re-arranger!---------");
Console.WriteLine("I take a positive number up to 10000, and find the highest number that can be made out of its digits.");
Console.WriteLine("Instructions: Enter a number up to 10000, and see the results!");
drLabel:
Console.Write("Your Number: ");
string input = Console.ReadLine();
int inputNumber = 0;
try { inputNumber = int.Parse(input); }
catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); goto drLabel; }
/*Placeholder code for the moment*/Console.WriteLine(inputNumber.ToString());
evaluate:
Console.Write("Do you want to exit? Yes/No: ");
if (Console.ReadLine().Equals("Yes"))
return 1;
else if (Console.ReadLine().Equals("No"))
{
goto drLabel;
}
else
{
return 1;
}
}
static void Main(string[] args)
{
Console.WriteLine("Welcome to the ACSL Competition Program. Choose a program to begin:");
Console.Write("\n\t");
Console.WriteLine("1\tDigit Re-arranger");
label:
Console.Write("\nProgram: ");
string input = Console.ReadLine();
int number = 0;
try { number = int.Parse(input); }
catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); goto label; }
if (number == 1)
{
Console.WriteLine("\n");
if (DigitRearranger() == 1)
{
goto label;
}
else if (DigitRearranger() != 1)
{
DigitRearranger();
}
}
else if (!number.Equals(1))
{
Console.WriteLine("Not a valid program.");
goto label;
}
//----------------
Console.ReadLine();
}
}
}
The underlying problem is that you're calling readline twice. The first time it gets the entered value, i.e. Yes, the second time you call it there is no data to read so it returns "". If you need to reuse the same input store it in a variable, i.e.
string inputVal = Console.ReadLine();
I hate goto statements, maybe you could restructure your code in to a while loop, something like:
bool exit = false;
while(!exit)
{
Console.Write("Your Number: ");
//Your main code
Console.Write("Do you want to exit? Yes/No: ");
if(Console.ReadLine() != "No")
exit = true;
}
In fact, you could get rid of the exit variable, just do while(true) and return if the user enters anything other than no.
I have a few suggestions:
Write your code to be more modular to improve readability. The Main() method should only drive the outer UI loop, each module provides its own UI.
Never use goto statements.
Don't use Console.Readline() inside an if condition (when not "Yes", it was called twice).
Here is my refactored version of your code:
class Program {
static void DigitRearranger()
{
string response = "";
int num;
do
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("---------Welcome to the Digit Re-arranger!---------");
Console.WriteLine("I take a positive number up to 10000, and find the highest number that can be made out of its digits.");
Console.WriteLine("Instructions: Enter a number up to 10000, and see the results!");
Console.ResetColor();
Console.Write("Your Number: ");
if (!int.TryParse(Console.ReadLine(), out num))
{
Console.WriteLine("Not a number. Press any key to continue");
Console.ReadKey();
continue;
}
//todo: reaarrange the number & print results
/*Placeholder code for the moment*/
Console.WriteLine(num);
Console.Write("Do you want to exit? Yes/No: ");
response = Console.ReadLine();
} while (response.ToLower() != "yes");
}
//UI driver only in Main method:
static void Main(){
string response = "";
do
{
Console.Clear();
Console.WriteLine("Welcome to the ACSL Competition Program. Choose a program to begin:");
Console.WriteLine("\n\t1\tDigit Re-arranger");
Console.WriteLine("\tq\tQuit");
Console.Write("\nProgram: ");
response = Console.ReadLine();
switch(response)
{
case "1":
DigitRearranger();
break;
case "q":
break;
default:
Console.WriteLine("Not a valid program. Press any key to continue");
Console.ReadKey();
break;
}
} while (response.ToLower() != "q");
Console.ReadLine();
}}