the question was :
The application should ask the user for the total number of tickets to be booked. while the booking the tickets if the total number of booked tickets exceeds the available tickets, the application should raise an exception. I don't know why it is not showing an error when I do this I came up with this solution:
using System;
namespace Ticket
{
class blah
{
public void abc()
{
int numberOfTickets;
int numberOfAvailableTickets=10;
int cost = 100;
int pay;
Console.WriteLine("how many tickets do you need");
numberOfTickets = Convert.ToInt32(Console.ReadLine());
try
{
if (numberOfTickets < numberOfAvailableTickets)
{
pay = 100 * numberOfTickets;
Console.WriteLine("Pay please");
Console.WriteLine(pay);
}
}
if( numberOfTickets>numberOfAvailableTickets)
{
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}
class Theater
{
static void Main(string[] args)
{
blah hi = new blah();
hi.abc();
Console.ReadLine();
}
}
}
I am not even sure that the code you show even compiles... try this
using System;
namespace Ticket
{
class blah
{
public void abc()
{
int numberOfTickets;
int numberOfAvailableTickets=10;
int cost = 100;
int pay;
Console.WriteLine("how many tickets do you need");
numberOfTickets = Convert.ToInt32(Console.ReadLine());
try
{
if( numberOfTickets>numberOfAvailableTickets)
throw new Exception ("Not enough Tickets available!");
pay = 100 * numberOfTickets;
Console.WriteLine("Pay please");
Console.WriteLine(pay);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}
class Theater
{
static void Main(string[] args)
{
blah hi = new blah();
hi.abc();
Console.ReadLine();
}
}
}
It throws an Exception if the the entered number exceeds the available tickets...
You have to use throw to raise an exception :
if( numberOfTickets>numberOfAvailableTickets)
throw new Exception();
The question is telling you to throw an exception if the booked number exceeds the available number.
So you don't need any try or catch in abc (I really hope these names aren't in your real code). You can also remove the if (numberOfTickets < numberOfAvailableTickets) (but keep the code inside.
Above:
pay = 100 * numberOfTickets;
move up:
if( numberOfTickets>numberOfAvailableTickets)
{
Inside the if put:
throw new ArgumentException("numberOfTickets is greater than numberOfAvailableTickets");
You can change ArgumentException to a custom exception if desired
Also note if you're using a catch, it must always be immediately after a try or another catch. You can't have an if between. See the documentation.
In Main, you can either catch that exception, or let it terminate the app (it's not clear from what you provided).
The problem is that you didn't explicitly throw the exception. Unless you do that, the compiler sees nothing wrong with your code, as by default it would only throw exceptions which actually affect the running state of your program.
Although this is a 'quick fix' so to say, just adding a throw new Exception(); where you want the exception to be thrown will work.
However, ideally, I would recommend creating a custom Exception class for this purpose. But the previous line should work anyway :)
I would suggest you to remove the try & catch and simple use MessageBox.
if (numberOfAvaiableTickets < numberOfTickets)
{
MessageBox.Show("Number of tickets exceeded", "ErrorWindow");
}
else
{
pay = 100 * numberOfTickets;
Console.WriteLine("Pay please");
Console.WriteLine(pay);
}
Related
I feel like this may be somewhat of a dumb question, but I've tried everything I currently know to do as a beginner of C# on this. Is there any way I can return a value into one I've already set to use elsewhere? Or am I just over-complicating this whole thing? Every time I try to set the already existing variable with one inside the curly brackets I get an error. Code I used below.
static double GetAmount()
{
double amount;
try
{
Console.WriteLine("Enter in the amount for the transaction: ");
double amount1 = Convert.ToDouble(Console.ReadLine());
return amount1;
}
catch (Exception ex)
{
bool f = true;
Console.WriteLine(ex.Message);
while (f == true)
try
{
Console.WriteLine("Enter the total in a proper format, no letters or spaces please. ");
double amount1 = Convert.ToDouble(Console.ReadLine());
f = false;
return amount1;
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
Console.WriteLine("Please try again.");
}
}
finally
{
return amount;
}
return amount;
}
You get two compilations errors and a warning. To understand them you must know that the finally-block is always executed before returning from the try- or catch-block. I.e., return amount1; would execute the statement in finally-block return amount;. But only one return-statement can be executed. Therefore, you get the message:
CS0157 Control cannot leave the body of a finally clause
and
CS0165 Use of unassigned local variable 'amount'
because the variable is declared but is not assigned a value yet when return is called.
Also, you get the warning
CS0162 Unreachable code detected
on the last code line, because the method will either be left by one of the previous return-statements or stay in the while-loop forever. Therefore, this last return statement can never be executed.
The bool flag f is redundant. There is no point in setting it to true before the return statement since the method is exited at the return-statement. This terminates the while-loop at the same time. If you want to exit the loop without returning, you can call break;.
Simplified version using try-catch:
static double GetAmount()
{
Console.Write("Enter in the amount for the transaction: ");
while (true) {
try {
double amount = Convert.ToDouble(Console.ReadLine());
return amount;
} catch (Exception ex) {
Console.WriteLine(ex.Message);
Console.Write("Enter the total in a proper format, no letters or spaces please: ");
}
}
}
The statement while (true) introduces an endless loop. Endless unless it is left by return, break or an unhandled exception (or the frowned upon goto command).
A better alternative is to use the TryParse method that does not throw an exception
static double GetAmount()
{
Console.Write("Enter the amount for the transaction: ");
while (true) {
if (Double.TryParse(Console.ReadLine(), out double amount)) {
return amount;
}
Console.Write("Enter the total in a proper format: ");
}
}
This version has the same functionality as yours, is safe, is 3 times smaller and is much easier to read.
See also: try-finally (C# Reference)
static double GetAmount()
{
double amount = 0;
try
{
Console.WriteLine("Enter in the amount for the transaction: ");
amount = Convert.ToDouble(Console.ReadLine());
}
catch (Exception ex)
{
bool f = true;
Console.WriteLine(ex.Message);
while (f)
try
{
Console.WriteLine("Enter the total in a proper format, no letters or spaces please. ");
amount = Convert.ToDouble(Console.ReadLine());
f = false;
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
Console.WriteLine("Please try again.");
}
}
return amount;
}
For many years my main language was Perl, and I regularly validated user input without a problem. Now I'm using a lot of C# and want to migrate toward the throw/catch style of validating user input and recovering/returning from thrown exceptions. I'm using a very naive (i.e., stupid) method of doing this, and feel an urgent need to move to something a little more mature and less stupid. I have copied a function that returns an integer from a prompt. I'm recovering from user errors by using the dreaded GOTO statement. What is the better way to do this?
Thanks, CC.
private static int GetInput(string v)
{
begin:
Console.Write(v);
string strradius = Console.ReadLine();
int intradius;
try
{
intradius = int.Parse(strradius);
if (intradius < 1)
throw new ArgumentOutOfRangeException();
}
catch (ArgumentNullException)
{
Console.WriteLine("You must enter a value.");
goto begin;
}
catch (FormatException)
{
Console.WriteLine("You must enter a valid number.");
goto begin;
}
catch (ArgumentOutOfRangeException)
{
Console.WriteLine("Your number is out of range");
goto begin;
}
catch (Exception ex)
{
Console.WriteLine(ex);
goto begin;
}
finally
{
Console.WriteLine("Okay");
}
return intradius;
}
First, a good rule of thumb as to when to use goto is never. Really, other than for a handful of very rare exceptional circumstances, you'd never want to use it.
Next, to your question, using exceptions to validate input is a bad idea in general. As most people pointed out it's expensive. Exceptions should be used to handle exceptional circumstances, so I would in fact not use them at all.
Instead, you can use a do-while loop, and repeat as long as the user inputs an incorrect input. You exit the loop once you get a proper input. If in case an exception occurs, you shouldn't really continue the process. Either handle it outside (i.e., no try-catch inside your method) or else if you must do a try-catch then simply print a message and exit the method. But I would not use exception handling for a method like this. Also it's a good idea to actually change the return type to bool, so you indicate to the outside world whether the method succeeded or not by the return type. You an use an out parameter to actually return the converted int.
private static bool GetInput(string msg, out int converted)
{
bool result = false;
converted = 0;
do
{
Console.Write(msg);
string str = Console.ReadLine();
result = int.TryParse(str, out converted);
if (result && converted < 1)
{
Console.WriteLine("Your number is out of range");
result = false;
}
if (!result && string.IsNullOrEmpty(str))
{
Console.WriteLine("You must enter a value.");
}
if (!result && !string.IsNullOrEmpty(str))
{
Console.WriteLine("You must enter a valid number.");
}
} while (!result);
return result;
}
Using goto statements in C# code is highly frowned-upon because it makes code difficult to read, debug, and maintain (for more info, read this). Loops, if/then statements, or method calls can be used instead of goto statements. Also, try \ catch blocks should be used sparingly, to catch exceptions that you are unable to handle.
In your case, we can use a while loop to continue to loop until a valid number is entered, and we can use the int.TryParse method to attempt to parse the string and get an integer result. This method returns a Boolean that indicates success, and takes an out parameter that will be set to the integer result.
My suggestion for your method would be to have it take in a string that will be used as a prompt for the user (asking them to enter a number), and return the integer result of their input.
For example:
private static int GetIntFromUser(string prompt, int minValue = int.MinValue,
int maxValue = int.MaxValue)
{
int result;
string errorMsg = $"ERROR: Input must be a valid number from {minValue} to {maxValue}";
while(true)
{
Console.Write(prompt);
string input = Console.ReadLine();
if (!int.TryParse(input, out result) || result < minValue || result > maxValue)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(errorMsg);
Console.ResetColor();
}
else
{
break;
}
}
return result;
}
In practice we can now call this method to get numbers from the user and we'll know they are valid without having to do any additional validation:
private static void Main()
{
// Age must be between 5 and 100
var age = GetIntFromUser("Please enter your age: ", 5, 100);
// Weight must be a positive number (minimum of zero)
var weight = GetIntFromUser("Please enter your weight: ", 0);
// No restrictions on favorite number
var favNum = GetIntFromUser("Enter your favorite whole number: ");
// This is a similar method I wrote to pause the program with a prompt
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
I'd write it something like this (though I'd probably give the user a chance to give up):
private static int GetInput(string v)
{
int intradius = 0; //needs to be initialized to keep compiler happy
while (true)
{
Console.Write($"{v}: ");
string strradius = Console.ReadLine();
if (!int.TryParse(strradius, out intradius))
{
Console.WriteLine($"An integer is required: [{strradius}] is not an integer");
}
else if (intradius < 1)
{
Console.WriteLine($"The entered number [{intradius}] is out of range, it must be one or greater");
}
else
{
break; //breaking out of the while loop, the input is good
}
}
return intradius;
}
For recoverable validation use conditional code/checks rather than relying on exceptions. Exceptions are expensive from a performance perspective primarily because they will generate a call stack.
Instead, look at something like:
private static int GetInput(string v)
{
Console.Write(v);
string strradius = Console.ReadLine();
if (string.IsNullOrEmpty(strradius)
{
Console.WriteLine("You must enter a value.");
return 0;
}
int intradius;
bool result = int.TryParse(strradius, out intradius);
if (!result)
Console.WriteLine("You must enter a valid number.");
else if (intradius < 1)
Console.WriteLine("Your number is out of range");
Console.WriteLine("Okay");
return intradius;
}
Personally, I like to wrap business logic results:
// Result container.
private class RadiusValidationResults
{
public bool IsSuccessful {get; private set;}
public int Radius {get; private set;}
public string FailureReason {get; private set;}
private RadiusValidationResults()
{ }
public static RadiusValidationResults Success(int result)
{
return new RadiusValidationResults { IsSuccessful = true, Radius = result };
}
public static RadiusValidationResults Failure(string failureReason)
{
return new RadiusValidationResults { FailureReason = failureReason };
}
}
// Validation business logic.
private static RadiusValidationResult ValidateRadius(string input)
{
if (string.IsNullOrEmpty(input)
return RadiusValidationResult.Failure("You must enter a value.");
int radius;
if (!int.TryParse(strradius, out radius))
return RadiusValidationResult.Failure("You must enter a valid number.");
else if (intradius < 1)
return RadiusValidationResult.Failure("Your number is out of range");
return RadiusValidationResult.Success(radius);
}
then your calling method that interacts with the Console:
private static int GetInput()
{
try
{
var result = ValidateRadius(Console.ReadLine());
if(!result.IsSuccessful)
Console.WriteLine(result.FailureReason);
else
Console.WriteLine("Okay");
return result.Radius;
catch // Here you can handle specific exception types, or bubble to a higher level. Log exception details and either terminate or present users with a generic "Whoops" and let them retry the operation.
{
Console.WriteLine("An unexpected error occurred.")
}
}
This means that your business logic (validating) can be unit tested without a hard dependency on the data source or outputs. (Console) The code should be succinct and easy to understand what is being done. A Try/Catch can be added to GetInput to handle the exceptional case. Generally let exceptions bubble to a high-enough level to handle them.
Based on this question (What benefit does the new Exception filter feature provide?).
The statement:
Exception filters are preferable to catching and rethrowing because
they leave the stack unharmed. If the exception later causes the stack
to be dumped, you can see where it originally came from, rather than
just the last place it was rethrown.
after doing some testing, I did not see the difference between both, the old and the new, I still see the exception from the place it was rethrown. So, or the information is not confirmed, I don't understand the Exception filters( that is why I am asking), or I am doing it wrong. Can you explaing me why this action filter are an advantage?
class specialException : Exception
{
public DateTime sentDateTime { get; } = DateTime.Now;
public int code { get; } = 0;
public string emailsToAlert { get; } = "email#domain.com";
}
then:
try
{
throw new specialException(); //line 16
throw new Exception("Weird exception");
//int a = Int32.Parse("fail");
}
catch (specialException e) when(e.code == 0)
{
WriteLine("E.code 0");
throw; // <-Line 23
}
catch (FormatException e)
{
WriteLine("cond1 " + e.GetBaseException().Message+" "+e.StackTrace);
throw;
}
catch (Exception e) //when (cond2)
{
Console.WriteLine("cond2! " + e.Message);
throw;
}
Result:
The advantages of exception filtering are more to do with when the filter doesn't match, not when it does match. If you remove all of the catch blocks except for the first one, and change the filter on the first catch block to when(e.code != 0), then the callstack of the exception would indicate it was thrown on line 16.
The old way of implementing this would be as follows:
try
{
throw new specialException(); //line 16
throw new Exception("Weird exception");
//int a = Int32.Parse("fail");
}
catch (specialException e)
{
if(e.code != 0)
{
WriteLine("E.code isn't 0");
return;
}
throw;
}
In this case, the call stack will indicate that the exception was thrown at the throw statement, rather than on line 16.
I'll give you a good real world example that I've used it for: deadlock retry loops.
Some APIs are nice and have a specific DeadlockException sort of thing -- others, like SOAP proxies, not quite. When you don't have one, exception filters are great to avoid needing to rethrow.
int retryCount = 0;
while(true)
{
try
{
// do stuff.
break;
}
catch(Exception ex) when(ex.Message == "Deadlock" && ++retryCount < 10)
{
// retry up to 10 times.
continue;
}
}
This saves you from having to throw a wrapper exception if a non-deadlock exception happens, or if the retry limit is hit.
I'm specifically looking for a solution for a console app, however answers for form apps are also welcome.
Would you be so kind as to help me with the following problem?
My Problem:
I want to create my own Exception that will catch any number from 5 to 9 when a user types one of them.
NOTE: I know I can solve this problem by simply playing with IF ELSE statements but I'm specifically looking for it to be CATCHed as Exception.
What I don't understand:
Once the user types in 5 for example, my own created exception catches it - What I don't understand is how to tell my created Exception Class what to catch, what to look for? Where do I type these numbers in my Exception and tell my Exception class that those numbers are exceptions?
If I wasn't clear enough, please let me know, I will try to rephrase myself.
You may benefit from an Exception tutorial.
It sounds like you are trying to do three things.
1 Read a number from a text input field.
2 Determine whether that is a valid number.
3 If the number is invalid, throw an exception.
//Read input
int i = -1;
i = int.TryParse(MyTextField.Text, out i);
if (i >= 5 && i <= 9)
throw new ArgumentOutOfRangeException("value", "Value cannot be between 5 - 9.");
Exceptions don't just happen. When your code throws an exception, for example if you try to divide by 0 and you get a DivideByZeroException - it means that some code somewhere has to have a line like throw new DivideByZeroException(); . (Admittedly, this is a simplification of the matter.)
So in order to throw the exception you want - you have to test the input and if it's not good then throw an exception.
And assuming you don’t mean that you need a custom Exception (e.g. FiveToNineException) - you can just use this:
if (i >= 5 && i <= 9)
{
throw new Exception("5 to 9 Exception");
}
Or:
if (i >= 5 && i <= 9)
{
Exception e = new Exception("5 to 9 Exception");
e.Data.Add("The number ", i);
throw e;
}
EDIT
For a very simple custom exception:
public class FiveToNineException : System.Exception
{
public FiveToNineException() : base() { }
}
and then you can have:
throw new FiveToNineException();
And:
try {/*Do something*/ }
catch (FiveToNineException ex) { }
For more information see this link for an answer to a question of mine.
If I understand you correct I think you should try something like:
if (yourNumber >= 5 && yourNumber <= 9)
{
throw new YourException(..);
}
But also see the comments. Your understanding of exceptions isn't correct.
The below code shows the basic example of a CustomException
class Program
{
static void Main(string[] args)
{
try
{
int x = Convert.ToInt32(Console.ReadLine());
if (x >= 5 && x <= 9)
{
CustomException e = new CustomException("Please Eneter Another Number");
throw e;
}
}
catch (CustomException ex)
{
Console.WriteLine(ex.Message);
}
}
}
public class CustomException : System.Exception
{
public CustomException(string txt)
: base(txt)
{
}
}
I want to return a default int value from main.
Consider the following:
using System;
class Class1
{
static int Main(string[] args)
{
int intReturnCode = 1;
int intRandNumber;
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
throw new Exception("ErrorError");
}
return intReturnCode;
}
}
When the exception is reached I don't get to set the returncode.
Is it possible to have a default return code inside of main?
Clarification: I have a program that is throwing Unhandled Exceptions. I have the application inside a try catch, however some errors (probably out of memory, stackoverflow etc) are still bubling up and causing my application to fail in production.
To fix this I've added code to capture unhandled exceptions.
This was added to main:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
And now I have this method that is reached when an unhandled exception occurs.
public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//here's how you get the exception
Exception exception = (Exception)e.ExceptionObject;
//bail out in a tidy way and perform your logging
}
The prblem is that I'm no longer in Main and I want to exit with a non-zero exit code.
An unhandled exception is implementation defined behaviour. Anything can happen; the CLR can decide to set the return code of the process as it sees fit, it can start a debugger, it can do whatever it wants. You cannot rely on any behaviour of any program that contains an unhandled exception.
If you want to have predictable behaviour, like determining what the return code is when the process ends, then there must be a total of zero unhandled exceptions.
If you have a third party component that is throwing unhandled out of memory exceptions then your best bet is: fix the bug in that component. If you can't do that then isolate the component into its own process or its own appdomain.
The question is really why you are throwing an exception in main instead of providing a return code that indicates an error? Instead of what you're doing, my code would look as follows:
static int Main(string[] args)
{
int intRandNumber;
try
{
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
Console.WriteLine("Got invalid random number!");
return 0;
}
}
catch (Exception exp)
{
Console.WriteLine("Strange ... an error occurred! " + exp.ToString());
return -1;
}
return 1;
}
As a rule of thumb you should never throw exceptions to control program flow. If you can, handle conditions like oops, I got the wrong number without throwing an exception.
Throwing an exception in the main thread ends execution without reaching the return: that's when you get the "Console application has stopped working, would you like to debug?" dialog from the operating system. The Main cannot return anything under these conditions, because there is nothing to return.
If you would like to return something when you get an exception, code your program like this:
// Put your implementation into a private method
private static int DoWork(string[] args) {
... // Do actual work, and throw exceptions if you need to
return intReturnCode;
}
// The Main method calls the implementation, and returns the value
// returned from the implementation if everything goes well.
// If an exception is thrown, however, Main could return another value
// of its choice.
public static int Main(string[] args) {
try {
return DoWork(args);
} catch {
return myDefaultReturnCode;
}
}
catch your exception and set return statement in finally block
using System;
class Class1
{
static int Main(string[] args)
{
try
{
int intReturnCode = 1;
int intRandNumber;
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
throw new Exception("ErrorError");
}
}
catch(Exception e)
{
// ...
}
finally
{
return intReturnCode;
}
}
}