How to split validation from input into two separate methods? - c#

I have the following method and I want to separate the input part from the validation part, i.e. I want to read the input in one method (ReadInput) and to assert that the input value is of type double in another method (AssertIsDouble). How can I do that?
public static double ReadInput()
{
double number = 0;
while (true)
{
if (Double.TryParse(Console.ReadLine(), out number) && number > 0)
{
return number;
}
else
{
Console.WriteLine("Please, input a number greater than zero (0).");
}
}
}
I tried the following but it didn't work:
public static double ReadInput()
{
double number = 0;
while (true)
{
AssertIsDouble(Console.ReadLine());
}
}
private static double AssertIsDouble(string input)
{
double number = 0.0;
if (Double.TryParse(input, out number) && number > 0)
{
return number;
}
else
{
Console.WriteLine("Please, input a number greater than zero (0).");
}
}

I'd use an out parameter along with returning a bool from the Assert method.
Disclaimer: The code is untested but should work.
public static double ReadInput()
{
double number;
while (!AssertIsDouble(Console.ReadLine(), out number))
{
Console.WriteLine("Please, input a number greater than zero (0).");
}
return number;
}
public bool AssertIsDouble(string input, out double number)
{
return (Double.TryParse(input, out number) && number > 0);
}
Note that if I was you I'd also rename the methods as they are a bit unclear at the moment:
ReadInput: Read what input, as what?
AssertIsDouble: Not a bad name but it also does additional checks.
Also note the problem with your original code is this loop:
while (true)
{
AssertIsDouble(Console.ReadLine());
}
You never check/assign the return value from the method call and never set a condition to break out of the loop, thus you have an infinite loop.

What I commonly do to get strongly typed (non-string) input from the user is to have a separate method that takes in a prompt to display to the user, an error prompt to display if they enter an incorrect value, and the min/max values allowed for the input. This greatly simplifies the main code body:
private static double GetDoubleFromUser(
string prompt = "Please enter a number: ",
string errorPrompt = " - Error: input must be a number between {0} and {1}: ",
double minValue = double.MinValue, double maxValue = double.MaxValue)
{
double value;
// Write the prompt text and get input from user
if (prompt != null) Console.Write(prompt, minValue, maxValue);
while (!double.TryParse(Console.ReadLine(), out value)
|| value < minValue || value > maxValue)
{
// If input can't be converted to a double or is out of range, keep trying
if (errorPrompt != null) Console.Write(errorPrompt, minValue, maxValue);
}
// Return converted input value
return value;
}
Now, in your main body of code, you would just do something like:
double input = GetDoubleFromUser("Please input the amount: ",
"- input must be a number greater than zero: ", 0);
Console.WriteLine($"You entered: {input}");
And the method handles the rest:

Related

How to restrict decimal in a console calculator in C#? Like when a decimal is inputted, it should print an error. But no if doesn't

Can someone help me modify my work? Help me add:
An error message when the user tries to enter decimal values.
A third operand for the calculator.
An error message when the user tries to enter any string value other than “exit”.
Here's my code:
class Program
{
static void Main(string[] args)
{
do
{
Console.Write("x = ");
string str = Console.ReadLine();
if (str == "exit")
{
Console.WriteLine("The Programme has stopped");
continue;
}
else
{
int x = Convert.ToInt32(str);
Console.Write("y = ");
int y = Convert.ToInt32(Console.ReadLine());
int sum = x / y;
Console.WriteLine("Result: {0}", sum);
}
}
while (true);
}
}
I'd be very grateful.
Here is a function you can use:
public static bool HasDecimals(decimal x) {
return Decimal.Round(x, 0) != x;
}
If I were going to do this, I'd create a function that I can use to handle most of the user interaction (emitting the prompt, parsing the input string, deciding if "Exit" was entered). In the code below, I kinda-sorta use the standard TryGetXxx pattern.
In this code below, if the TryGetDecimalValueWithPrompt returns true, then a properly parsed number is returned in the output. If it returns false, then the user has chosen to quit.
So, I start with that function:
public static bool TryGetDecimalValueWithPrompt(string prompt, out decimal outputValue)
{
while (true)
{
Console.Write(prompt + " > ");
var response = Console.ReadLine();
if (response.Equals("exit", StringComparison.OrdinalIgnoreCase) || response.Equals("quit", StringComparison.OrdinalIgnoreCase))
{
outputValue = 0.0m;
return false;
}
if (decimal.TryParse(response, out outputValue))
{
return true;
}
//otherwise, failure, so try again
Console.WriteLine("Sorry, incorrect format, try entering a correctly formatted decimal again");
}
}
The while(true) statement says Loop Forever. In this case, Forever lasts until the user has entered a properly formatted number or one of the "exit" keywords.
Then I construct my program around it:
if (!TryGetDecimalValueWithPrompt("Enter the first operand", out var operand1))
{
return;
}
if (!TryGetDecimalValueWithPrompt("Enter the second operand", out var operand2))
{
return;
}
if (operand2 == 0.0m)
{
Console.WriteLine("Sorry, you can't divide by zero");
return;
}
Console.WriteLine($"The result of op1/op2 is {operand1 / operand2}");
If you don't want to allow decimals being entered, change the TryGetDecimalValueWithPrompt function to work with integers instead:
public static bool TryGetIntValueWithPrompt(string prompt, out int outputValue)
{
while (true)
{
Console.Write(prompt + " > ");
var response = Console.ReadLine();
if (response.Equals("exit", StringComparison.OrdinalIgnoreCase) || response.Equals("quit", StringComparison.OrdinalIgnoreCase))
{
outputValue = 0;
return false;
}
if (int.TryParse(response, out outputValue))
{
return true;
}
//otherwise, failure, so try again
Console.WriteLine("Sorry, incorrect format, try entering a correctly formatted integer again");
}
}
If you work with integers, remember that integer division always yields an integer. For example, if you use integers in 7 / 2, the result will be 3, not 3.5. If you want 3.5, do something like 7 / (decimal) 2 (at that point, you are dividing an integer by a decimal and you'll get a decimal).
By the way, if you wanted to prompt for the operator (+, -, *, or /), you could create a TryGetOperator function in the same pattern and just check whatever you get from the user with something like:
var operators = new[] { "+", "-", "*", "/" };
bool goodOperator = operators.Contains(inputFromUser);

Error: 'Program.Coefficient()': not all code paths return a value [duplicate]

This question already has answers here:
C# compiler error: "not all code paths return a value"
(9 answers)
Closed 3 years ago.
I don't want the else statement to return a value, but just run the method again. However, I get compile time error
'Program.Coefficient()': not all code paths return a value.
How do I get rid of this error?
This is the code:
public static double Coefficient()
{
string string1 = Console.ReadLine();
string[] stringArray = string1.Split('^');
double[] doubleArray = new double[stringArray.Length];
for (int i = 0; i < stringArray.Length; i++)
{
doubleArray[i] = Double.Parse(stringArray[i]);
}
if (doubleArray.Length == 2)
{
double coefficient = Math.Pow(doubleArray[0], doubleArray[1]);
return coefficient;
}
else if (doubleArray.Length == 1)
{
double coefficient = doubleArray[0];
return coefficient;
}
else
{
Console.WriteLine("Please follow the specified input form (a^b).");
Console.ReadKey();
Coefficient();
}
}
The error means that at least one flow possibility does not return a value, which is the last 'else' in your case.
The last line should be then:
return Coefficient();
As your function returns value, that means from each if..else block you need to return double value.
Here you are not returning any value from else block. You need to return double value from else block
else
{
Console.WriteLine("Please follow the specified input form (a^b).");
Console.ReadKey();
return Coefficient(); // This will call recursively same function. for recursion use return Coefficient() ;
//return 0; //If you don't want recursion, then comment above line and return 0
}
I would prefer to refactor your code to minimize code present in Coefficient() method. something like ,
public static double Coefficient()
{
while (true)
{
string string1 = Console.ReadLine();
string[] stringArray = string1.Split('^');
double[] doubleArray = Array.ConvertAll(stringArray, double.Parse);
if (doubleArray.Length == 2)
{
double coefficient = Math.Pow(doubleArray[0], doubleArray[1]);
return coefficient;
}
else if (doubleArray.Length == 1)
{
return doubleArray[0];
}
Console.WriteLine("Please follow the specified input form (a^b).");
}
}
I suggest to redesign the routine (I can't see any need in recursion). You can implement a loop in order to keep asking until user inputs (Console.ReadLine()) valid value:
public static double Coefficient() {
while (true) {
string input = Console.ReadLine();
string[] items = input.Split('^');
if (items.Length == 1) {
if (double.TryParse(items[0], out double A))
return A; // One valid value
}
else if (items.Length == 2) {
if (double.TryParse(items[0], out double A) &&
double.TryParse(items[1], out double B))
return Math.Pow(A, B); // Two valid values
}
// Neither one valid value, nor two valid values pattern
Console.WriteLine("Please follow the specified input form (a^b).");
// No need in "Console.ReadKey();" - the routine will stop on Console.ReadLine()
}
}
Be careful with Double.Parse since it throws exception on invalid string (e.g. if user inputs "bla-bla-bla"); use Double.TryParse instead.

Creating a "warning" when trying to calculate X/0

I want to make a calculator that asks what you want to do, e.g. add, subtract, etc. It should then use if-statements to perform the different kinds of calculations.
But now when I have gotten to division, I'm wondering how to handle division by 0. I want the program to warn the user when he/she enters a 0, saying something like "sorry you can't divide by 0".
I still want it to calculate the result if the denominator isn't 0.
The error i get is that i can't write:
if (Num02 == "0") because I can't use ints or doubles etc.
How do I fix this in a nice way to show my class/teacher next week?
Here's my code:
using System;
namespace Calculator
{
class MainClass
{
static void Main(string[] args)
{
Start:
int Num01;
int Num02;
string Answer;
Console.WriteLine("What do you want to do?");
Answer = Console.ReadLine();
if (Answer == "Division")
{
Console.WriteLine("Write number");
Num01 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Divided by?");
Num02 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(Num01 + "/" + Num02 + "=" +
(Num01 / Num02));
}
}
}
}
the error i seem to get is that i cant write:
"if (num02 == "0")" because i cant use ints or doubles etc.
You were most certainly on the right track. By adding quotes around the "0", you were comparing a variable of type int (Num02) with a string. Instead, use a literal 0 (without quotes):
if (Num02 == 0)
{
// print warning here
}
else
{
// do division and print result
}
I suggest extracting method for the user input (where we can check syntax - what if user put bla-bla-bla instead of number, extra condition(s) - we don't accept 0 as a second number etc.):
private static int ReadValue(string title,
Func<int, bool> extraCondition = null,
string extraConditionText = null) {
int result;
while (true) { // keep on asking until correct input provided
Console.WriteLine(title);
if (!int.TryParse(Console.ReadLine(), out result)) // syntax check
Console.WriteLine("Syntax error, please, input integer value");
else if (extraCondition != null && !extraCondition(result)) // extra check if any
Console.WriteLine(string.IsNullOrEmpty(extraConditionText)
? "Incorrect value"
: extraConditionText);
else
return result;
}
}
Then you can put
static void Main(string[] args) {
while (true) {
int Num01;
int Num02;
Console.WriteLine("What do you want to do?");
string Answer = Console.ReadLine().Trim();
if (string.Equals(Answer, "Quit", StringComparison.OrdinalIgnoreCase)) {
break;
}
else if (string.Equals(Answer, "Division", StringComparison.OrdinalIgnoreCase)) {
Num1 = ReadValue("Write number");
Num2 = ReadValue("Divided by?", x => x != 0, "Sorry you can't divide by 0");
Console.WriteLine($"{Num1} / {Num2} = {Num1 / Num2}");
}
else {
Console.WriteLine("Sorry, it's an incorrect option");
}
}
}

Ending a loop by sentinel and parsing an input string as an integer

I am trying to continuously ask user for a number between 300-850. When the user enters a valid number, add it to the total and ask again. If the number is invalid, display an error. Before program ends, display the average of total number by amount of times of input. End program if user enters a sentinel value. I don't know how to check if user enters a sentinel value.
using System;
class CreditScores
{
static void Main()
{
var iterations = 0;
double total = 0;
int sum = 0;
double average = 0;
int count = 0;
Console.WriteLine("Enter value between 300 to 850.");
int first = int.Parse(Console.ReadLine());
//trying to get it to stop when sentinel value reached.
while (iterations < 1000)
{
iterations++;
Console.WriteLine("Enter value between 300 to 850.");
int input = int.Parse(Console.ReadLine());
//not sure how to check if input is a number or not
if(input == integer)
{
if( input < 850 && input > 300 )
{
total +=input;
}
}
else
{
break;
}
}
total = sum + total;
Console.WriteLine("Total is {0}", total);
average = total / count;
Console.WriteLine("The average is {0}", average);
}
}
Modification/fix of Your Method
Also, I would read all the way to the end for the more robust method you could use.
First thing I would change:
while (iterations < 1000)
{
...
}
To this (which we are not done yet, read to the end):
while (input != "calculate") // or some other string
{
...
}
Then, before the while starts, make input a string.
string input = "";
while (input != "calculate") // or some other string
{
...
}
Now, we declared an input variable that is already an int later on. Let's fix that.
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
{
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
{
total += value;
}
}
else
{
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
Now, we need to put it together and do some cleaning.
int total = 0;
int numbersEntered = 0;
string input = "";
while (input != "calculate")
{
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
{
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
{
total += value;
numbersEntered++;
}
}
else
{
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
}
Console.WriteLine("Total is {0}", total);
double average = (double)total / numbersEntered;
Console.WriteLine("The average is {0}", average);
(I know, long answer. But it should help you step through the problem in the future. Also, I wrote this all by memory, I can't guarantee it will compile.)
Update: just tested it, works as expected.
A more Robust Method
Lastly, and this is really the coolest method in my opinion, use a List<int> and some extension methods.
List<int> values = new List<int>();
string input = "";
while (input != "calculate")
{
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value = 0;
if (int.TryParse(input, out value))
// Clearly it's a valid integer at this point
if (value < 850 && value > 300)
values.Add(value);
else
{
// Was outside our range
}
else
// Wasn't a number, might be our sentinel.
if (input == "calculate")
break;
else
{
// Throw an error or something.
}
}
Console.WriteLine("Total is {0}", values.Sum());
Console.WriteLine("The average is {0}", values.Average());
Advantages to this method? It saves a list of the values entered, allowing you to do more with them that you cannot do with the method you currently have. It also uses the int.Sum() and int.Average() extension methods rather than your own math.
What is this int.TryParse(string, out int) sorcery?
The int.TryParse(string, out int) method (as defined by MSDN) will take an input string, and return a boolean value that indicates if it would make a valid int structure or not.
In the case that the string is a valid int, then the int parameter is filled with the integer representation of the string.
I.e.:
string myString = "100";
int value = 0;
if (int.TryParse(myString, out value))
Console.WriteLine("myString was a valid int: {0}", value);
else
Console.WriteLine("myString was not a valid int.");
This version will return true and print: myString was a valid int: 100.
Example 2:
string myString = "blah";
int value = 0;
if (int.TryParse(myString, out value))
Console.WriteLine("myString was a valid int: {0}", value);
else
Console.WriteLine("myString was not a valid int.");
This version will return false, and print myString was not a valid int.. The value variable would also be 0.
Warning:
When using int.TryParse(string input, out int value), do not rely on the value parameter as 0 to indicate failure. If the input is "0", then the value will also be 0, and the method will return true.
You want to set the condition of your while loop to something that a user can trigger as false (the sentinel).
Then put a for loop inside that if you want to do a set number of iterations, for loops are better for situations where you know how many iterations you're doing.
BUT if you want to stick to while loops only, here's a quick code snippet you could use:
while (input != 0 && iterations < 1000) //or some sentinel value you choose
{
//Your logic here, now the loop will quit if if the user enters 0
//OR you run out of iterations
}
using System;
class CreditScores
{
static void Main()
{
double total = 0;
int sum = 0;
int count = 0;
Console.WriteLine("Enter value between 300 to 850.");
int first = int.Parse(Console.ReadLine());
//trying to get it to stop when sentihel value reached.
for (iterations = 0; iterations < 1000; iterations++)
{
Console.WriteLine("Enter value between 300 to 850.");
int input;
// Check number is integer
if (int.TryParse(Console.ReadLine(), out input)
{
if(input > 300 && input < 850)
{
total +=input;
}
}
else
{
break;
}
count++;
}
total = sum + total;
Console.WriteLine("Total is {0}", total);
double average = total/count;
Console.WriteLine("The average is {0}", average);
Console.ReadLine(); // Either this or run with Ctrl-F5
}
}
The behaviour would be to add the totals until the user entered something that couldn't be parsed, and then exit.
Does this work?
string sentinalValue = "done";
string input = "";
while (iterations < 1000 && input != sentinalValue)
{
iterations++;
Console.WriteLine("Enter value between 300 to 850.");
input = Console.ReadLine();
int value;
if (int.TryParse(input, out value))
{
if( value < 850 && value > 300 )
{
total +=input;
}
}
else
{
Console.WriteLine("That is not a number!");
}
}

Checking user input in C#

I just wrote my first C# console application, I am still a beginner. Anyway, I tried the code below and it seems to work, its for solving quadratic equations. I'd like to add code for a situation whereby a user inputs a string instead of an integer and give an error message any ideas as to how to implement this?
namespace Quadratic_equation
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("welcome to seyi's quadratic calculator!!!");
Console.Write("a:");
double a = Convert.ToInt32(Console.ReadLine());
Console.Write("b:");
double b = Convert.ToInt32(Console.ReadLine());
Console.Write("c:");
double c = Convert.ToInt32(Console.ReadLine());
if ((b * b - 4 * a * c) < 0) {
Console.WriteLine("There are no real roots!");
}
else {
double x1 = (-b + Math.Sqrt((b*b)-4*a*c)) /2*a;
double x2 = (-b + Math.Sqrt((b*b)-4*a*c)) /2*a;
Console.WriteLine("x:{0}",x1);
Console.WriteLine("y:{0}",x2);
}
Console.ReadKey();
}
}
}
You can use Int32.TryParse method to check your string is a valid integer or not. This method returns a boolean value for your conversation is succeed or not.
Converts the string representation of a number to its 32-bit signed
integer equivalent. A return value indicates whether the conversion
succeeded.
And I don't understand why you want to keep as double the return value of Convert.ToInt32 method. These factors (a, b, c) should be integer, not double.
int a;
string s = Console.ReadLine();
if(Int32.TryParse(s, out a))
{
// Your input string is a valid integer.
}
else
{
// Your input string is not a valid integer.
}
This Int32.TryParse(string, out int) overload uses NumberStyle.Integer as default. That means your string can have one of these;
Trailing white spaces
Leading white spaces
Leading sign character
Check out int.TryParse
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
else
{
if (value == null) value = "";
Console.WriteLine("Attempted conversion of '{0}' failed.", value);
}
Use a try-catch block in a do-while loop:
bool goToNextNum = false;
do
{
try
{
double a = Convert.ToInt32(Console.ReadLine());
goToNextNum = true;
}
catch
{
Console.WriteLine("Invalid Number");
}
} while (goToNextNum == false);
This will loop until a is a valid number.

Categories