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();
}
Related
I'm making a library program that asks for users to input the amount of books checked out and the amount of days they are over due. If its under or equal to 7 days they are charge 10 cents for each book over due after 7 days its 20 cents for each book. We are supposed to use more than one method and I get two errors:
Use of unassigned local variable 'totalCharge'
There is no argument given that corresponds to the required formal parameter 'daysOverdue' of Program.charge(double,double,double)'
I think I know what the first error means but I thought I already declared it a variable in the first line.
Here's the code so far:
static void Main(string[] args){
double totalCharge;
Console.WriteLine("Please enter the number of books checked out.");
double booksChecked = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Please enter the number of days they are
overdue.");
double daysOverdue = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Your total charge for {0} days overdue is {1}.",
daysOverdue, totalCharge.ToString("C"));
Console.ReadKey();
totalCharge = charge();
}
private static double charge (double daysOverdue, double booksChecked,
double totalCharge)
{
if (daysOverdue <= 7)
{
return totalCharge = booksChecked * daysOverdue * .10;
}
else
{
return (booksChecked * .70) + (booksChecked) * (daysOverdue - 7)
* (.20);
}
}
}
}
Your code has a number of problems, which I'll review here. My corrections are at the end of this answer. I recommend putting your code and mine side by side and reviewing the differences carefully.
First, you cannot read the value out of a variable before you have assigned a value. You must assign something to it first.
You need to call charge(...) before printing out the value of totalCharge.
Second, you don't need to pass the value of totalCharge to your charge(...) method: it returns the total charge! So remove that parameter entirely.
Third, you need to pass parameters to the charge method.
Fourth, you had some formatting problems. Please review my code to see how I've formatted my code differently. If a line of code is continued onto the next line, use indentation to reflect this. According to C# conventions, function names should be capitalized.
Lastly, this isn't necessarily a problem, but it doesn't look 'right': in two places, you are assigning Convert.ToInt32(...) to a double. Why? Those should be integers.
static void Main(string[] args)
{
Console.WriteLine("Please enter the number of books checked out.");
double booksChecked = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Please enter the number of days they are overdue.");
double daysOverdue = Convert.ToInt32(Console.ReadLine());
// assign before printing out value
// pass the two parameters into the function
double totalCharge = Charge(daysOverdue, booksChecked);
Console.WriteLine("Your total charge for {0} days overdue is {1:C}.",
daysOverdue,
totalCharge);
Console.ReadKey();
}
private static double Charge(double daysOverdue, double booksChecked)
{
if (daysOverdue <= 7)
{
return booksChecked * daysOverdue * .10;
}
else
{
return (booksChecked * .70) + booksChecked * (daysOverdue - 7) * (.20);
}
}
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?
I'm trying to check if the user's response is a double or an int, but the int is specific, whereas the double is not, as I probably made a right mess of explaining it, here's the code:
Console.WriteLine("\n 2) Q: How old is Sally? \n");
int nSallyAge = Convert.ToInt32(Console.ReadLine());
double dSallyAge = Convert.ToDouble((nSallyAge));
if (nSallyAge == 62 || dSallyAge == 62.0)
{
// Increase Score
sUser1Score++;
Console.WriteLine("\n A: Correct, Sally's age is 62, you have been awarded 1 point. \n");
Console.ReadLine();
}
What I'm trying to do, is instead of dSallyAge HAS to equal 62.0, it just has to equal any double figure.
I would approach this problem by first creating a method that gets a double from the user (that will, of course, also accept an int). This removes error handling from your main code.
NOTE in the code below, Math.Truncate can be replaced by Math.Floor, with the same result:
private static double GetDoubleFromUser(string prompt)
{
double input;
while (true)
{
if (prompt != null) Console.Write(prompt);
if (double.TryParse(Console.ReadLine(), out input)) break;
Console.WriteLine("Sorry, that is not a valid number. Please try again.");
}
return input;
}
Then, in my main code, I would get the number from the user, and use the Math.Truncate method to just read the first part of the double passed in by the user (this is what it sounds like you want to do). This means that if the user enters anything from 62 to 62.0 to 62.999, it will truncate the result to '62':
double nSallyAge = GetDoubleFromUser("2) Q: How old is Sally? ");
if (Math.Truncate(nSallyAge) == 62)
{
// Increase Score
sUser1Score++;
Console.WriteLine("A: Correct, Sally's age is 62, you have been awarded 1 point.");
Console.ReadLine();
}
Other alternative ways to use this are:
int sallyAge = Math.Truncate(GetDoubleFromUser("2) Q: How old is Sally? "));
if (sallyAge == 62)
{
// Increase Score
sUser1Score++;
Console.WriteLine("A: Correct, Sally's age is 62, you have been awarded 1 point.");
Console.ReadLine();
}
Or, you could use an input function that returns an int in the first place:
private static int GetIntFromUser(string prompt)
{
return Math.Truncate(GetDoubleFromUser(prompt));
}
In your code above, you are converting the input to an integer and then converting the int result to a double.
Assuming that you are only allowing numerical values to be entered, why not try something like this. This will identify if the input contained decimals or not:
string input = Console.ReadLine();
int iSallyAge;
double dSallyAge;
if (!Int32.TryParse(input, iSallyAge))
{
dSallyAge = Double.Parse(input);
}
You should be using Double.TryParse to parse the user input to a double and then test that value to see whether it's equal to 62.0.
double age;
if (double.TryParse(Console.ReadLine(), out age) && age == 62.0)
{
// age is 62.
// ...
}
First of all I am a beginner in C#, I have just started to play around with it as that's what my University course requires.
My problem is an assignment question which says:
h) To test if a number entered has an integer value. Hint: The number will have to be of type Double. If, for example, the number is 2.5 that doesn’t have an integer value but 2 does. You will need to use Convert.ToInt32(TheNumber) to convert the Double to an Int then compare the two.
double a, b, result;
Console.WriteLine("Input a number");
a = Convert.ToDouble(Console.ReadLine());
b = Convert.ToInt32(a);
This is what I have at the moment and I don't know how to compare these 2 to test which one is an integer. I am pretty sure that you have to use an if statement but how to tell C# to test which of these 2 numbers is an integer and which one isn't!
Any help is highly appreciated :)
Update:
I'd do it like this:
double d;
int i;
Console.WriteLine("Input a number");
d = Convert.ToDouble(Console.ReadLine());
i = Convert.ToInt32(d);
if(i == d) Console.WriteLine("It is an integral value");
This means: if you convert a double to an integer, it will lose all its digits after the decimal point. If this integer has the same value as the double, then the double had no digits after the decimal point, so it has an integer value.
You can use TryParse method which returns boolean
double mydouble;
int myInt;
string value = Console.ReadLine();
if (double.TryParse(value, out mydouble))
{
//This is double value, you can perform your operations here
}
if (int.TryParse(value, out myInt))
{
//This is Int value, you can perform your operation here
}
Should be like this:
double d;
int i;
Console.WriteLine("Input a number");
d = Convert.ToDouble(Console.ReadLine());
i = Convert.ToInt32(d);
if(i == d) Console.WriteLine("It is an integral value");
I think you can use TryParse with do while loop
int number;
string value;
do
{
Console.Write("Enter a number : ");
value =Console.ReadLine();
if (!Int32.TryParse(value, out number))
{
Console.WriteLine("Wrong Input!!!!");
}
}while (!Int32.TryParse(value, out number));
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)...