Use of try - catch for taking care of letters - c#

I have written a program that will emulate how a cash register works.
I would need some help with how to make the program take care of, if for example the user enters letters instead of numbers.
Then i would like the letters that the user entered were lost and the user receives a new opportunity to start from scratch.
I have written some code for it using try and catch, but not sure how it should be written.
class Program
{
static void Main(string[] args)
{
int cash = 0;
double totalAmount = 0;
uint subTotal;
int exchange;
double roundingOffAmount;
Console.Write("Please enter a total amount for the cash register : ");
totalAmount = double.Parse(Console.ReadLine());
if (totalAmount < 1)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("\nTotalamount needs to be more\n");
Console.ResetColor();
Environment.Exit(0);
}
try
{
Console.Write("Please enter cash for the cash register: ");
cash = int.Parse(Console.ReadLine());
if (cash < totalAmount)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("\nCash needs to be more than totalAmount\n");
Console.ResetColor();
Environment.Exit(0);
Console.WriteLine();
}
else
{
// Do nothing
}
}
catch (FormatException)
{
Console.Write("\nSorry you typed in a letter you need to type in a number");
Console.WriteLine();
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("\nSomething went wrong, please try again");
Console.ResetColor();
Console.WriteLine();
Main(args);
}
subTotal = (uint)Math.Round(totalAmount);
roundingOffAmount = subTotal - totalAmount;
exchange = cash - (int)totalAmount;
Console.WriteLine("\n Receipt"
+ "\n ------------------------------------"
+ "\n Totalt \t: \t {0:c}", totalAmount);
Console.WriteLine(" RoundingOffAmount\t: \t {0:f2}", roundingOffAmount);
Console.WriteLine(" To pay \t: \t {0:c}", subTotal);
Console.WriteLine(" Cash \t: \t {0:c}", cash);
Console.WriteLine(" Exchange \t:\t {0:c}", exchange
+ "\n ------------------------------------");
Console.WriteLine();
}
}
Any help is warmly received.

Firstly - and more importantly - for currency values, you should be using decimal rather than double. Decimal floating point numbers are more appropriate for monetary values, which are exactly represented in decimal - whereas binary floating point types (double and float) are more appropriate for "natural" values such as height and weight, which will never have an absolutely precise measured value anyway. See my articles on binary floating point and decimal floating point for more details.
Next, rather than using exception handling for this validation, I suggest you use decimal.TryParse - which returns whether or not it was successful. That way you don't have to use try/catch just to catch a pretty predictable exception which can easily be avoided. For example:
decimal value;
while (!decimal.TryParse(Console.ReadLine(), out value))
{
Console.WriteLine("Sorry, that wasn't a valid number");
}

You should use int.TryParse. If the input is not a valid integer, this will return false.
If it returns false, you can use this as a way of prompting the user to enter another value in.
EDIT
As Jon Skeet pointed out, you really should use decimal type when dealing with currency.

Use try parse:
decimal totalAmount;
bool ok = decimal.TryParse(outConsole.ReadLine(), out totalAmount);
if(!ok){
//Bad input. Do something
}else{
//input ok, continue
}
Use the same approach to parse the integer.

instead of
totalAmount = double.Parse(Console.ReadLine());
do
boolean isDouble = double.TryParse(Console.ReadLine(), out totalAmount);
then check
if(isDouble)...

Related

C# Prohibiting user typing Words instead of numbers

Having some problems with my Console Calculator
I want to prohibit user inputing a words instead of numbers.
I wrote this code and its converting words to zero but i want user to type a number instead of words. And if user still typing words program should ask user to type number.
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("----------------------");
Console.WriteLine("------Calculator------");
Console.WriteLine("----------------------");
do
{
double num1 = 0;
double num2 = 0;
double result = 0;
bool result0;
Console.WriteLine("Enter number one: ");
try
{
double.TryParse(Console.ReadLine(), out num1);
if ()
{
Console.WriteLine("Incorrect number!\nType another number:");
num1 = Convert.ToDouble(Console.ReadLine());
}
}
catch (Exception e)
{
}
Console.WriteLine("Enter number two: ");
num2 = Convert.ToDouble(Console.ReadLine());
You have to use double.TryParse() inside a if condition with negation operator.
If you want to force user to show "Incorrect number!\nType another number:" message till the user enters correct integer, use while() loop instead of if() condition.
while (!double.TryParse(Console.ReadLine(), out num1))
Console.WriteLine("Incorrect number!\nType another number:");
Why we should use double.TryParse() inside if condition?
double.TryParse(), parse string value to double and return true if conversion succeeded or not.
In your case, if user enters word instead of number then conversion will fail and use of !(negation) will iterate the loop again.

C# code executes even when variable not assigned

As you can probably tell from my question, I am very new to coding. I am trying to make a calculator that computes some formulas that are used in physics. However, the code runs the formula before the user has time to enter a value for A, in this example at least. Here is the example:
case "f = ma":
Console.WriteLine("Type the value for M in KG:");
var FM = Console.Read();
Console.WriteLine("Type the value for A in M/S:");
var FA = Console.Read();
var FMARes = FM * FA;
Console.WriteLine("Your answer (in Newtowns) is " + FMARes);
break;
How am I able to check whether a value has been assigned to the variable A, and only run the formula after the variable has an assigned value? Thanks.
You need to use ReadLine instead of Read. You also need to do another ReadLine at the bottom so the user can see the result. And...you should validate that the user entered a valid number. This could be refactored a bit to avoid duplicate code - etc. - but see if this works for you! Good luck!!
static void Main(string[] args)
{
double fm;
double fa;
// Use ReadLine instead of Read
Console.WriteLine("Type the value for M in KG:");
var input = Console.ReadLine();
// Now you need to cast it to a double -
// -- but only if the user entered a valid number
if (!double.TryParse(input, out fm))
{
Console.WriteLine("Please enter a valid number for M");
Console.ReadLine();
return;
}
Console.WriteLine("Type the value for A in M/S:");
input = Console.ReadLine();
if (!double.TryParse(input, out fa))
{
Console.WriteLine("Please enter a valid number for A");
Console.ReadLine();
return;
}
// Now we have valid values for fa and fm
// It's a better programming practice to use the string format
// intead of + here...
Console.WriteLine($"Your answer (in Newtowns) is {fm * fa}");
// You need another read here or the program will just exit
Console.WriteLine("Press Enter to end the program");
Console.ReadLine();
}

How do I accept blanks in C#?

I am trying to create a program which calculates the result of exams by taking in the number of marks obtained in each subject. It is almost done but I'm encountering an error that is, if the user just presses enter instead of entering a value, the application wont proceed. Also is there any way to shortening this code?
Console.WriteLine("Danyal's result calculator for students of class IX. Enter the marks requested, if not applicable leave blank and press enter :)");
Console.Write("Enter your Urdu marks: ");
int urdu = int.Parse(Console.ReadLine());
Console.Write("Enter your Maths marks: ");
int maths = int.Parse(Console.ReadLine());
Console.Write("Enter your English Literature marks: ");
int lit = int.Parse(Console.ReadLine());
Console.Write("Enter your Biology marks: ");
int bio = int.Parse(Console.ReadLine());
Console.Write("Enter your Chemistry marks: ");
int chem = int.Parse(Console.ReadLine());
Console.Write("Enter your Islamiat marks: ");
int isl = int.Parse(Console.ReadLine());
Console.Write("Enter your Physics marks: ");
int physics = int.Parse(Console.ReadLine());
Console.Write("Enter your Computer marks: ");
int comp = int.Parse(Console.ReadLine());
Console.Write("Enter your English Language marks: ");
int lang = int.Parse(Console.ReadLine());
Console.Write("Enter your Pakistan Studies marks: ");
int pst = int.Parse(Console.ReadLine());
int total = urdu + maths + lit + lang + bio + chem + physics + isl + comp + pst;
Console.WriteLine("Your total marks are {0} out of 1000", total);
float percentage = total * 100 / 1000;
Console.WriteLine("Your percentage is: {0}%",percentage);
Console.WriteLine("Note: the percentage has been rounded off. Please share this program with other classmates, also I am open to suggestions for creating more helpful programs.");
Console.ReadLine();
I'm not sure what you would want to do in case the user leaves it blank, or enters an invalid value, but you could do something like this.
Dictionary<string,int> grades = new Dictionary<string, int>
{
{ "Urdu", 0 },
{ "Maths", 0 },
{ "English", 0 },
{ "Biology", 0 },
{ "Chemistry", 0 },
{ "Islamiat", 0 },
{ "Physics", 0 },
{ "Computer", 0 },
{ "English Language", 0 },
{ "Pakistan Studies", 0 },
};
foreach (string grade in grades.Keys.ToArray())
{
Console.WriteLine(string.Format("Enter your {0} marks: ", grade));
int mark;
if (int.TryParse(Console.ReadLine(), out mark))
grades[grade] = mark;
}
int total = grades.Sum((g) => g.Value);
In this example, if bad input is used the grade will default to 0. If you wanted to you could change the if try parse to a loop and request a good value until one is entered as well.
This is a clear case of not adhering to the DRY principle. You are repeating operations that are essentially the same, don't do that. Refactor the code so that common patterns or behaviors are solved in one single place.
How would you do that here?
Create a method that prompts the user to enter certain information. What does the user need? A descriptive message of what he has to do. What does the user need to do? Enter a valid input. Ok, with that in mind, the following prototype of a method seems like a good starting point:
private static int GetUserInput(string message) { ... }
Hmmm...enter a valid input. This means we need some sort of validation, so again let's think of how we can solve this:
private static int ValidateUserInput(string input) { ... }
Is this good enough? Well...no quite. What happens if the user enters an incorrect number? There is no convenient way of conveying that the input is not valid to the caller. We could return -1, or we could throw an exception, but both seem offish.
The best solution would be to return two values; one telling us if the input is valid and another telling us what the input is. In c# this isn't very striaghtforward (at least until c# 7 comes along). The way to do it is using out arguments:
private static bool ValidateUserInput(string message, out int input) { ... }
Now this method serves our purpose perfectly. The return value tells us if the input is valid and the out argument input gives us the validated value (or we simply ignore it if the validation failed).
Why are you creating an int variable for each mark if you essentially only want sums and averages? Lets create a List<int> where we store all the marks.
Another option, if you want to keep track of what mark corresponds to what subject, would be to use a Dictionary<string, key> where the key would be the subject name and the value its corresponding mark. But lets use List<int> for now.
With all that in mind we can build up our solution:
public static void ComputeMarksSummary()
{
var marks = new List<int>();
marks.Add(GetUserInput("Enter your Urdu marks: "));
marks.Add(GetUserInput("Enter your Maths marks: : "));
marks.Add(GetUserInput("Enter your English Literature marks: "));
marks.Add(GetUserInput("Enter your Biology marks: "));
marks.Add(GetUserInput("Enter your Chemistry marks: "));
marks.Add(GetUserInput("Enter your Islamiat marks: "));
marks.Add(GetUserInput("Enter your Computer marks: "));
marks.Add(GetUserInput("Enter your English language marks: "));
marks.Add(GetUserInput("Enter your Pakistan studies marks: "));
var total = marks.Sum();
Console.WriteLine("Your total marks are {0} out of 1000", total);
Console.WriteLine("Your percentage is: {0}%", total/10.0); //note the 10.0 to force double division, not integer division where 44/10 would be 4 not 4.4
Console.WriteLine("Note: the percentage has been rounded off. Please share this program with other classmates, also I am open to suggestions for creating more helpful programs.");
//WRONG! Percentage is not rounded off, its truncated: 9/10 is 0 in integer division.
Console.ReadLine();
}
private static int GetUserInput(string message)
{
int mark;
while (true)
{
Console.WriteLine(message);
var input = Console.ReadLine();
if (!ValidateUserInput(input, out mark))
{
Console.WriteLine("Invalid input, please try again.");
}
else
{
return mark;
}
}
}
private static bool ValidateUserInput(string message, out int input)
{
//left as an excerice. Hint: look into int.TryParse(...);
//here you could decide if a blank input should be valid and parsed as zero.
}
Wow, now that seems a lot cleaner....but hey, we can still do a little bit better. Whats up with all those marks.Add(....)? Can't we refactor the code some more? Well yes, we are essentially asking always the same thing, only the subject name changes. How about we do something like this:
public static void ComputeMarksSummary(IEnumerable<string> subjectNames)
{
var marks = new List<int>();
foreach (var subject in sujectNames)
{
marks.Add(GetUserInput(string.Format("Enter your {0} marks: ", subject)));
}
var total = marks.Sum();
Console.WriteLine("Your total marks are {0} out of 1000", total);
Console.WriteLine("Your percentage is: {0}%", total/10.0); //note the 10.0 to force double division, not integer division where 44/10 would be 4 not 4.4
Console.WriteLine("Note: the percentage has been rounded off. Please share this program with other classmates, also I am open to suggestions for creating more helpful programs.");
Console.ReadLine();
}
And you could call it like this:
ComputeMarksSummary(new string[] { "Urdu", "Maths", ... );
Doesn't that seem so much cleaner?

Overloaded Methods with User Input (ReadLine())

I am working through learning C# myself (not homework) and am confused about method overloading when there is user input.
I am doing an exercise that allows the user to input a bid amount for an item. I need to include 3 overloaded methods (int, double, string). (The exercise says to use double not decimal.)
I know how to write the overloaded methods, my confusion comes with the user input. If I accept the input (ReadLine) as a string, it chooses the string method, if I accept the input as a int, the int method is called. How do I deal with this? Do I use tryParse? How can I do this with 3 possible input methods (int, double, string)?
Also, to add a frustrating twist, for the string to be accepted it must be numeric and preceded with '$' sign or numeric followed by "dollars". I am hoping that I completed that correctly in the code below. Wasn't sure how to trim by string, so I had to do it by character...
Hoping for a basic/simple explanation, as I haven't learned anything too fancy yet.
Thank you!
namespace Auction
{
class Program
{
static void Main(string[] args)
{
string entryString;
//int entryInt; // do I need this?
//int entryDouble; // do I need this?
double bidNum;
const double MIN = 10.00;
Console.WriteLine("\t** WELCOME TO THE AUCTION! **\n");
Console.Write("Please enter a bid for the item: ");
entryString = Console.ReadLine().ToLower();
double.TryParse(entryString, out bidNum); // this turns it into a double...
BidMethod(bidNum, MIN);
Console.ReadLine();
}
private static void BidMethod(int bid, double MIN)
{ // OVERLOADED - ACCEPTS BID AS AN INT
Console.WriteLine("Bid is an int.");
Console.WriteLine("Your bid is: {0:C}", bid);
if (bid >= MIN)
Console.WriteLine("Your bid is over the minimum {0} bid amount.", MIN);
else
Console.WriteLine("Your bid is not over the minimum {0} bid amount.", MIN);
}
private static void BidMethod(double bid, double MIN)
{ // OVERLOADED - ACCEPTS BID AS A DOUBLE
Console.WriteLine("Bid is a double.");
Console.WriteLine("Your bid is: {0:C}", bid);
if (bid >= MIN)
Console.WriteLine("Your bid is over the minimum {0} bid amount.", MIN);
else
Console.WriteLine("Your bid is not over the minimum {0} bid amount.", MIN);
}
private static void BidMethod(string bid, double MIN)
{ // OVERLOADED - ACCEPTS BID AS A STRING
string amount;
int amountInt;
if (bid.StartsWith("$"))
amount = (bid as string).Trim('$'); // Remove the $
if (bid.EndsWith("dollar"))
amount = bid.TrimEnd(' ', 'd', 'o', 'l', 'l', 'a', 'r', 's');
else
amount = bid;
Int32.TryParse(amount, out amountInt); // Convert to Int
Console.WriteLine("Bid is a string.");
Console.WriteLine("Your bid is: {0:C}", bid);
if (amountInt >= MIN)
Console.WriteLine("Your bid is over the minimum {0} bid amount.", MIN);
else
Console.WriteLine("Your bid is not over the minimum {0} bid amount.", MIN);
}
}
}
Assuming that you are looking to support various ways of entering a dollar amount, then I would suggest your idea of using TryParse could work:
First use int.TryParse - as int is most restrictive (doesn't
allow decimal point etc)
Second use double.TryParse
Finally, if neither of those work, keep as a string.
I think that replacing int and double versions with a decimal version would be more appropriate since decimal is more convenient for storing money values (search SO for more details).
So, read input, search for a dollar sign, if there is none, use decimal.TryParse() and a decimal overload else use the string overload.
As there is no difference in processing a number whether it contains a dollar sign or not, I would do the following.
...
string entryString = Console.ReadLine();
BidMethod(entryString, 10.00m); // m stands for decimal, d for double
...
private static void BidMethod(string bid, decimal min)
{
decimal number;
if (decimal.TryParse(bid.Replace("$", ""), out number))
{
Console.WriteLine("Your bid is: {0:C}", bid);
if (number >= min)
Console.WriteLine("Your bid is over the minimum {0} bid amount.", min);
else
Console.WriteLine("Your bid is not over the minimum {0} bid amount.", min);
}
}
Based on my understanding and your comments:
Hence you need (or the exercise requests) to accept int, double or string only.
I think you would need to first check if the input value containing $ or not, if so then you can call the string function.
Then you will check the value as int using Int32.TryParse if succeeded then call the int function
Last step is by checking the value as double by using Double.TryParse
Double's length is way more than int, that's why you should be checking int first
using System;
using static System.Console;
namespace Auction
{
class Program
{
static void Main(string[] args)
{
string entryString;
decimal bidNum;
const decimal MIN = 10.00m;
Console.Write("Please enter a bid for the item: ");
entryString = Console.ReadLine().ToLower();
decimal.TryParse(entryString, out bidNum); // this turns it into a double...
BidMethod(bidNum, MIN);
Console.ReadLine();
}

How do I throw and exception using `if` and `else` if the user enter something that isn't a valid integer?

I'm writing a program that adds numbers. The program takes input from the user as an integer value and gives him a total of both numbers. But I want that when the user enters any character besides the number, a custom error is written to the console. How do you do that with if and else?
My code:
class Program
{
static void Main(string[] args)
{
double firstnum, secondnum, total;
Console.WriteLine("FIRST NUMBER");
firstnum = Convert.ToDouble(Console.ReadLine());
if (Console.ReadLine == char)
{
Console.WriteLine("error... error wrong keyword, enter only numbers...");
}
Console.WriteLine("SECOND NUMBER");
secondnum = Convert.ToDouble(Console.ReadLine());
total = firstnum + secondnum;
Console.WriteLine("TOTAL VALUE IS =" + total);
Console.ReadLine();
First read the string into a string variable. Then use TryParse to turn it into a number. It'll return false if the string is no valid number, which you can use to display your error.
var firstNumAsString = Console.ReadLine();
int firstNum;
if (!int.TryParse(firstNumAsString, out firstNum))
{
Console.WriteLine("error... error wrong keyword, enter only numbers...");
return;
}
If you want to throw an exception instead of just displaying an error, use int.Parse. It'll throw a FormatException or an OverflowException if the input isn't valid.

Categories