How can I handle an exception in C#? [duplicate] - c#

This question already has answers here:
Parse v. TryParse
(8 answers)
Closed 5 years ago.
I'm trying to handle an exception to avoid my program crash if double.Parse(string) tries parsing invalid values (such as strings instead of numbers). Here's what I've got:
do
{
//asking customer the amount of shirts he would like to buy any shirts they want.
numbershirtString = Console.ReadLine(); // customer types in amount of shirts they want.
numbershirts = double.Parse(numbershirtString);
keepLooping = true;
if (numbershirts < 10)
{
Console.WriteLine("You would be buying " + numbershirts + " shirts");
keepLooping = false;
}
if (numbershirts > 10)
{
Console.WriteLine("You cannot order more than 10 shirts. Please try again.");
keepLooping = true;
}
} while (keepLooping);
I would appreciate your help. Thank you in advance!

Use double.TryParse() instead. It returns true of false depending on the outcome:
double val;
bool success = double.TryParse("red", out val);
if(success)
{
// val contains a parsed value
}
else
{
// could not parse
}

To handle an exception, in C# like similar in other languages, you can use the try..catch block.
Look at the simplest syntax:
try
{
//Try to run some code.
}
catch
{
//Do something if anything excepted.
}
If you're interested to retrieve which exception breaked the code:
try
{
//Try to run some code.
}
catch (Exception ex)
{
//Do something ex was thrown.
}
If you change the type of ex to something inheriting the base class Exception you'll handle only all the exception of that type:
try
{
//Try to run some code.
}
catch (StackOverflowException ex)
{
//Do something ex was thrown because you overflowed the stack.
}
But instead of talking about try..catch block which you can find out more about on Google, I suggest you to use the method double.TryParse(string, out double).
Its syntax is a little bit different than double.Parse, but effectively it does the same in a different way.
It returns true if your input is valid, else it returns false, whereas in the first parameter you have just to pass your string input and in the second one is required an output reference to the result variable:
double x = 0;
string number = "125.3";
if (double.TryParse(number, out x))
Console.WriteLine("Your number is " + x.ToString());
else
Console.WriteLine("Your input isn't valid");

Maybe this is a little advanced for you, but if you are feeling in a clever mood, you can define a class that handles the parsing of user input. That way you can keep that logic separated from your main program (see separation of concerns).
public class UserEntry
{
private readonly string _originalValue;
public UserEntry(string input)
{
_originalValue = input;
}
public bool IsInt
{
get
{
return int.TryParse(_originalValue, out var dummy);
}
}
public int ToInt()
{
return ToInt(default(int));
}
public int ToInt(int defaultValue)
{
int result;
bool ok = int.TryParse(_originalValue, out result);
return ok ? result : defaultValue;
}
public override string ToString()
{
return _originalValue;
}
static public implicit operator UserEntry(string input)
{
return new UserEntry(input);
}
static public implicit operator Int32(UserEntry input)
{
return input.ToInt();
}
}
If we use implicit conversion operators it makes things very simple. For example, all of these are now legal:
UserEntry entry = Console.ReadLine();
if (!entry.IsInt) continue;
if (entry < 10) return entry;
If we apply this to your example, it shortens your code a bit, and arguably makes it a bit clearer as well.
public class Program
{
private const int MaximumOrder = 10;
public static void Main()
{
var n = AskForNumberOfShirts();
Console.WriteLine("OK, I'll order {0} shirts.", n);
}
public static int AskForNumberOfShirts()
{
while (true)
{
Console.WriteLine("Enter the number of shirts to order:");
UserEntry entry = Console.ReadLine();
if (!entry.IsInt)
{
Console.WriteLine("You entered an invalid number.");
continue;
}
if (entry > MaximumOrder)
{
Console.WriteLine("{0} is too many! Please enter {1} or fewer.", entry, MaximumOrder);
continue;
}
return entry;
}
}
}
Notes:
I doubt you can order half a shirt, so I am using an int instead of a double to store the number of shirts.
I refactored the logic branches to use opportunistic return, a.ka. Guard Pattern. See this article for why I do this.
I extracted the constant value 10 to its own symbol, MaximumOrder. This should get you a couple points on the assignment.
Output:
Enter the number of shirts to order:
22
22 is too many! Please enter 10 or fewer.
Enter the number of shirts to order:
sdlfkj
You entered an invalid number.
Enter the number of shirts to order:
9
OK, I'll order 9 shirts.
Working example on DotNetFiddle

Related

How to ask the user to input numbers only in integer?

I want to ask the user to input a number including an if statement option were if he puts letters the last question will be asked again
I've tried this but seemingly it work only for strings
Console.Write("Write a number:");
int num = Convert.ToInt32(Console.ReadLine());
if (!int.TryParse(age, out num))
while(!int.TryParse(age, out num))
{
Console.WriteLine(...);
// ....
}
Let's extract method for this: we are going to ask user to input valid value until he or she provides it. So we have a loop:
private static int ReadInteger(string question) {
// Keep asking...
while (true) {
if (!string.IsNullOrWhiteSpace(question))
Console.WriteLine(question);
// ... until valid value provided
if (int.TryParse(Console.ReadLine(), out int result))
return result;
Console.WriteLine($"Sorry, not a valid integer value; please, try again.");
}
}
Then you can use it as
int age = ReadInteger("Please, input age");
I have a function that I'm using in my current project that might help you out, it just checks if the input string only contains numbers:
bool isDigitsOnly(string inputString)
{
foreach (char c in inputString)
{
if (c < '0' || c > '9')
return false;
}
return true;
}
You might have to modify it a little bit to fit your needs, but it should work well enough

Too many methods very similar

I have many methods which are very similar as shown in the code below:
public static void ReadFromKeyboard(string label, out int retVal)
{
try
{
Console.Write(label);
retVal = int.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert int value.");
ReadFromKeyboard(label, out retVal);
}
}
public static void ReadFromKeyboard(string label, out float retVal)
{
try
{
Console.Write(label);
retVal = float.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert float value.");
ReadFromKeyboard(label, out retVal);
}
}
public static void ReadFromKeyboard(string label, out double retVal)
{
try
{
Console.Write(label);
retVal = double.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please insert double value.");
ReadFromKeyboard(label, out retVal);
}
}
By the other hand, I don't know which method I will call. I'll discorver it only at runtime.
Is there any way I could rewrite these many methods into a single method named something like "ReadFromKeyboard" which returns either an int, a float or a double depending on the type which is passed to it as a parameter?
Thank you!
As other answers have shown, you can eliminate the duplicated code by a variety of techniques, all of which are horrible and you should not do them.
In particular, do not attempt to use generics to solve this "problem". Generics are for situations where the code is generic. That is why they are called generics! That is, the code operates the same on every possible type. Your example is the opposite of generic code; you have different rules for a small number of types, and the way to handle that situation is to do exactly what you have already done: implement one method per different rule.
I say "problem" in quotes because you do not actually have a problem to solve here, so stop trying to solve it. Writing half a dozen similar short methods is not a major burden on authors or maintainers.
Now, that said, your code is also not as good as it could be and you should rewrite it. The correct way to write your code is:
public static int ReadInteger(string label)
{
while(true)
{
int value;
Console.Write(label);
string read = Console.ReadLine();
bool success = int.TryParse(read, out value);
if (success)
return value;
Console.WriteLine("Please type an integer value.");
}
}
The problems with your original implementation are:
Do not use exception handling as mainline control flow. Do not catch an exception if the exception can be avoided. That's what TryParse is for.
Do not use recursion as unbounded looping. If you want an unbounded loop, that's what while(true) is for. Remember, C# is not tail recursive by default!
Do not use out parameters without need. The method logically returns an integer, so actually return an integer. Rename it so that you do not get collisions with other read methods. There is no compelling benefit to making the caller write Read<int> over ReadInteger, and many compelling benefits to avoiding the out param.
I've tried to implement the code according to Eric Lippert recipes. The code below
does not use exception handling as mainline control flow
does not use recursion at all
does not use output parameters without need
.
private static void Main(string[] args)
{
int intValue = ReadFromKeyboardInt32("enter int");
float floatValue = ReadFromKeyboardSingle("enter float");
double doubleValue = ReadFromKeyboardDouble("enter double");
Console.WriteLine($"{intValue}, {floatValue}, {doubleValue}");
}
public static Double ReadFromKeyboardDouble(string label) =>
ReadFromKeyboard(label, (text) => (Double.TryParse(text, out var value), value));
public static Int32 ReadFromKeyboardInt32(string label) =>
ReadFromKeyboard(label, (text) => (Int32.TryParse(text, out var value), value));
public static Single ReadFromKeyboardSingle(string label) =>
ReadFromKeyboard(label, (text) => (Single.TryParse(text, out var value), value));
public static T ReadFromKeyboard<T>(string label, Func<string, (bool, T)> tryParse)
{
for (; ; )
{
Console.Write($"{label}: ");
var result = tryParse(Console.ReadLine());
if (result.Item1)
{
return result.Item2;
}
Console.WriteLine($"Please enter valid {typeof(T).Name} value");
}
}
Instead of listing all the possible types (which you might not know beforehand), it is possible to use the System.Convert class, specially the Convert.ChangeType() method. As a proof of concept you can use a method like this:
public static void ReadFromKeyboard<T>(string label, out T result) {
Type targetType = typeof(T);
Console.Write($"{label}: ");
string input = Console.ReadLine();
object convertedValue = Convert.ChangeType(input, targetType);
result = (T)convertedValue;
}
You can use this method like this:
public static void Main(string[] args) {
ReadFromKeyboard("enter a double", out double d);
ReadFromKeyboard("enter an int", out int i);
Console.WriteLine($"double: {d}");
Console.WriteLine($"int: {i}");
}
This way it is possible to use any type you want (assuming it is supported by the Convert class). Obviously you can add exception handling and a do-while loop in the ReadFromKeyboard method if you like.
If you want to rely on overload resolution for the runtime to decide which method to call, then you must have a separate method for each type you will support. That's how it works.
On the other hand, if you can allow the user to supply at least a little type information, we can improve things a bit with generics by removing try/catch and using a real return statement. You'd call it like this:
var myNumber = ReadFromKeyboard<double>("Enter a double: ");
And the code would look like this:
public static T ReadFromKeyboard<T>(string label, int maxRetries = int.MaxValue)
{
while (maxRetries >= 0)
{
Console.Write(label);
if (typeof(T) == typeof(int))
{
int result;
if (int.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
if (typeof(T) == typeof(float))
{
float result;
if (float.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
double result;
if (double.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
decimal result;
if (decimal.TryParse(Console.ReadLine(), out result)) return (T)(object)result;
}
else
throw new InvalidOperationException("Unsupported type");
maxRetries--;
}
throw new InvalidOperationException("Too many bad inputs");
}
But you have to do some really janky casting and type checking to make it work. There is still a potential this can throw an exception, which it seems like you want to avoid, but if your user sits there for more than 2 billion attempts, I doubt they'll be very surprised.

Converting Celcius to Fahrenheit - Double.TryParse

I have a successful clean code that does a conversion of Celcius to Fahrenheit using Double.Parse. However, I was curious on how it would look if I did a Double.TryParse but I can't seem to figure out how to complete the code. Once executed, I am able to present "Invalid Code", in my "if, else" but I still get this after my Invaild Output...
Please enter a value for conversion:
30x
Invalid code
The conversion from Celcius to Fahrenheit is: 32
using System;
using System.Text;
namespace CSharpBasics
{
class Program
{
public static double CelciusToFarenheit(string celciusTemperature)
{
//Converting string to a double for conversion
double celcius;
if (Double.TryParse(celciusTemperature, out celcius))
{
}
else
{
Console.WriteLine("Invalid code");
}
double fahrenheit = (celcius * 9 / 5) + 32;
return fahrenheit;
}
public static void Main(string[] args)
{
Console.WriteLine("Please enter a value for conversion:");
var input = CelciusToFarenheit(Console.ReadLine());
Console.WriteLine("The conversion from Celcius to Fahrenheit is: " + input);
}
}
}
You should verify your input before the conversion to make sure you never display invalid result for an invalid input but return a message notifying the wrong input first. Something like this:
public static double CelciusToFarenheit(double celcius)
{
double fahrenheit = (celcius * 9 / 5) + 32;
return fahrenheit;
}
public static void Main(string[] args)
{
Console.WriteLine("Please enter a value for conversion:");
var input = Console.ReadLine();
double celcius;
if (Double.TryParse(input, out celcius))
{
var result = CelciusToFarenheit(celcius);
Console.WriteLine("The conversion from Celcius to Fahrenheit is: " + result);
}
else
{
Console.WriteLine("Invalid code");
}
}
The method signature public static double CelciusToFarenheit(...) says that this method returns a value - and currently it does.
However, your program flow has to consider invalid input - and thus you need 2 information:
was the entered value a valid value
what's is the value
There are different methods to solve this issue, at least the following:
return a struct or object that holds both information
use the return value and indicate invalid results with exceptions
split the single method into 2 methods, one for checking validity and one for delivering the value.
Let's discuss the 3 options:
3) This might be looking nice, but when you look at Double.TryParse(), you'll likely introduce duplicate code. And when you look at the Main method, the abstraction level will not be the same.
2) Exceptions shall be used for exceptional cases. Wrong user input seems to be a rather usual thing. Not ideal for this case.
1) Sounds quite ok, except that the method might be responsible for 2 things: checking validity and calculating.
To implement that, you don't even need to write a new struct or class. You can simply use Nullable<double> or double?.
Since you're talking about clean code (potentially referring to R.C. Martin), I would start by looking at the main method. Basically I would say the code follows the IPO principle (input, processing, output). However, one line does 2 things:
var input = CelciusToFarenheit(Console.ReadLine());
Also, the variable name input is not so useful here, because it's not the input of the user, but the output after processing.
Proposal for that part:
public static void Main(string[] args)
{
var userInput = GetCelsiusInputFromUser();
var output = CelciusToFarenheit(userInput);
PrintOutput(output);
}
Also, the conversion method does not only convert, but print partial results as well:
Console.WriteLine("Invalid code");
I'd remove that piece and leave it to the output method to handle that case.
Full code:
using System;
namespace CSharpBasics
{
class Program
{
public static double? CelciusToFarenheit(string celciusTemperature)
{
//Converting string to a double for conversion
double celcius;
if (Double.TryParse(celciusTemperature, out celcius))
{
double fahrenheit = (celcius * 9 / 5) + 32;
return fahrenheit;
}
else
{
return null;
}
}
public static void Main(string[] args)
{
var userInput = GetCelsiusInputFromUser();
var output = CelciusToFarenheit(userInput);
PrintOutput(output);
}
private static void PrintOutput(double? output)
{
if (output == null)
{
Console.WriteLine("Invalid code");
}
else
{
Console.WriteLine("The conversion from Celcius to Fahrenheit is: " + output);
}
}
private static string GetCelsiusInputFromUser()
{
Console.WriteLine("Please enter a celsius value for conversion:");
var userInput = Console.ReadLine();
return userInput;
}
}
}
BTW: if you don't have a technical issue, https://codereview.stackexchange.com/ might be better suited for questions regarding clean code.

How to know what user entered in C# [duplicate]

This question already has answers here:
C# testing to see if a string is an integer?
(10 answers)
Closed 6 years ago.
For Ex:
cw("enter anything");
//we dont know if user entered int or string or any other datatype so we would check as,
if(userEntered == int){}
if(userEntered==string){}
In other way: If user enters for example int value so we convert it and save it but if we dont know what user entered, how will we judge or detect?
For a console application taking in user input, assume its a string to begin with as string will be able to hold whatever the input is.
If needed, then you can parse it to another datatype such as ints or floats.
public class MainClass
{
public static void Main(string[] args)
{
String value = Console.ReadLine();
var a = new MainClass();
if a.IsNumeric(value){
//your logic with numeric
}
else
{
//your logic with string
}
}
public Boolean IsNumeric(String value){
try
var numericValue = Int64.Parse(value);
return true;
catch
return false;
}
In this case there is a separate function, which tries to convert it to number, if successful return true, otherwise false. With this you will avoid further code repetition to check if your value is numeric or not.
Once you have your string input, you can use TryParse to see if it is an int or a decimal (among other things)...
string userEntered = Console.ReadLine();
int tempInt;
decimal tempDec;
if(int.TryParse(userEntered, out tempInt))
MessageBox.Show("You entered an int: " + tempInt);
else if(decimal.TryParse(userEntered, out tempDec))
MessageBox.Show("You entered a decimal: " + tempDec);
else MessageBox.Show("You entered a string: " + userEntered);
There is no strict rule for that, User just enters a string value. It could be null or empty string or any other string, which might or might not be convertible to int or decimal or DateTime or any other datatype. So you just have to parse the input data and check whether its convertible to a datatype or not.
You can read user input through
console.readline
to check if it is a string or integer ,you can do something like this
by default user input is string
check the following code snippet
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
string input = Console.ReadLine();
Console.WriteLine(input);
int num2;
if (int.TryParse(input, out num2))
{
Console.WriteLine(num2);
}
}
}
Here is an example to check if user enters integer or string value:
Console.WriteLine("Enter value:");
string stringValue = Console.ReadLine();
int intValue;
if(int.TryParse(stringValue, out intValue))
{
// this is int! use intValue variable
}
else
{
// this is string! use stringValue variable
}
Console.WriteLine("enter someting");
string read = Console.ReadLine();
Console.Readline() read user input and will return a string
From here try to convert/parse it to other data type.

Telephone number validation

I have this code to validate a phone number but it looks a bit awkward. I'm guessing theres a better way to go about this. How can I make this more efficient?
public static bool validTelephoneNo(string telNo)
{
bool condition = false;
while (condition == false)
{
Console.WriteLine("Enter a phone number.");
telNo = Console.ReadLine();
if (telNo.Length > 8)
{
if (telNo.StartsWith("+") == true)
{
char[] arr = telNo.ToCharArray();
for (int a = 1; a < telNo.Length; a++)
{
int temp;
try
{
temp = arr[a];
}
catch
{
break;
}
if (a == telNo.Length - 1)
{
condition = true;
}
}
}
}
}
return true;
}
Don't try and do this yourself, use a library where someone has already done the hard work for you, such as libphonenumber.
Example:
public static bool validTelephoneNo(string telNo)
{
PhoneNumber number;
try
{
number = PhoneNumberUtil.Instance.Parse(telNo, "US"); // Change to your default language, international numbers will still be recognised.
}
catch (NumberParseException e)
{
return false;
}
return number.IsValidNumber;
}
This library will handle parsing and formatting phone numbers from different countries. Not only will this ensure that the number is valid in the relevant country, it will also allow you to filter out premium numbers and "fake" numbers (such as 555 in the US).
Your goal can be easily achieved using regular expressions:
public static bool validTelephoneNo(string telNo)
{
return Regex.Match(telNo, #"^\+\d{1,7}$").Success;
}
This pattern is exactly as stated: consists of integers, is less than 8 digits in length and has a plus at the start, and also this pattern can be modified if conditions somehow more complex.
try
Console.WriteLine("Enter a phone number.");
bool isValid = new System.Text.RegularExpressions.Regex(#"^[+]\d{1,7}$").IsMatch(Console.ReadLine());
Where the regex checks whether there is only a single number (1 to 7 digits) with + in front of them read. The drawback, this way you cannot further processed, you might need to read the line from console to a new variable.

Categories

Resources