Home

Exception Handling

   

Introduction to Exceptions

 

Overview

Imagine you want to write a program that requests a number from the user, multiplies the number by 2, and displays the result. The form of this program can be designed as follows:

Introduction to Exceptions

private void button1_Click(object sender, EventArgs e)
{
	double Number;

	Number = double.Parse(textBox1.Text);

	textBox2.Text = (Number * 2).ToString();
}

This looks like an easy request. When it comes up, the user is asked to simply type a number. The number would then be multiplied by 2 and display the result. Imagine that a user types something that is not a valid number, such as the name of a country or somebody's telephone number.

 

Since this program was expecting a number and it is not prepared to multiply a string to a number, it would produce an error. Whenever the compiler is handed a task, it would try to perform the assignment. If it can't perform the assignment, for any reason it is not prepared for, it would throw an error. As a programmer, if you can anticipate the type of error that could occur in your program, you can catch the error yourself and deal with it by telling the compiler what to do when this type of error occurs.

   

ApplicationApplication: Introducing Exception Handling

  1. Start Microsoft Visual Studio
  2. To create a new application, on the main menu, click File -> New Project...
  3. Select Windows Forms Application
  4. Set the Name to ClarksvilleIceCream1
  5. Click OK
  6. To create a new form, on the main menu, click Project -> Add Windows Form...
  7. In the Add New Item dialog box, set the name of the form to Calculation, and click Add
  8. Design the new form as follows:
     
    Clarksville Ice Scream - Difference Calculation
    Control Name Text Additional Properties
    Label Label   Order Total:  
    TextBox Text Box txtOrderTotal 0.00 TextAlign: Right
    Modifier: Public
    Label Label   Amount Tended:  
    TextBox Text Box txtAmountTended 0.00 TextAlign: Right
    Button Button btnCalculate Calculate  
    Label Label   Difference:  
    TextBox Text Box txtDifference 0.00 TextAlign: Right
    Button Button btnClose Close  
  9. Double-click the Calculate button
  10. Implement the Click event as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double TotalOrder,
               AmountTended = 0.00,
               Difference;
    
        // Get the value of the total order. Actually, this value 
        // will be provided by the main form
        TotalOrder = double.Parse(this.txtOrderTotal.Text);
    	
        // The amount tended will be entered by the user
    	AmountTended = double.Parse(this.txtAmountTended.Text);
    
        // Calculate the difference of both values, assuming 
        // that the amount tended is higher
        Difference = AmountTended - TotalOrder;
    
        // Display the result in the Difference text box
        this.txtDifference.Text = Difference.ToString();
    }
  11. Return to the Calculation form
  12. Double-click the Close button
  13. Implement the event as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  14. In the Solution Explorer, right-click Form1.cs and click Rename
  15. Type ClarksvilleIceCream.cs and press Enter
  16. Right-click the form and click Properties
  17. In the Properties window, change the form's Text to Clarksville Ice Cream
  18. Design the form as follows:
     
    Clarksville Ice Cream: Form Design
    Control Name Text Additional Properties
    GroupBox   grpIceCream    
    Label Label   Order Date:  
    TextBox Text Box txtOrderDate    
    Label Label   Order Time:  
    TextBox Text Box txtOrderTime    
    Label Label   Flavor:  
    TextBox Text Box txtFlavor    
    Label Label   Container:  
    TextBox Text Box txtContainer    
    Label Label   Ingredient:  
    TextBox Text Box txtIngredient    
    Label Label   Scoops:  
    TextBox Text Box txtScoops 1 TextAlign: Right
    Label Label   Order Total:  
    TextBox Text Box txtOrderTotal 0.00 TextAlign: Right
    Button Button btnCalculate Calculate  
    Button Button btnNewOrder New Order  
    Button Button btnMoneyChange Money Change  
    Button Button btnClose Close  
  19. Double-click the Calculate Total button to access its Click event
  20. Implement it as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double priceContainer = 0.00,
               priceIngredient = 0.00,
               priceScoops = 0.00,
               orderTotal = 0.00;
        int numberOfScoops = 1;
    
        // Find out what container the customer requested
        // The price of a container depends on which one the customer selected
        if (txtContainer.Text == "Cone")
            priceContainer = 0.55;
        else if (txtContainer.Text == "Cup")
            priceContainer = 0.75;
        else
            priceContainer = 1.15;
    
        // If the customer selected an ingredient, which is not "None", add $.95
        if (txtIngredient.Text != "None")
            priceIngredient = 0.95;
    
        // Get the number of scoops
        numberOfScoops = int.Parse(this.txtScoops.Text);
    
        if (numberOfScoops == 2)
            priceScoops = 2.55;
        else if (numberOfScoops == 3)
            priceScoops = 3.25;
        else
            priceScoops = 1.85;
    
        // Make sure the user selected a flavor, 
        // otherwise, there is no reason to process an order
        if (txtFlavor.Text != "")
            orderTotal = priceScoops + priceContainer + priceIngredient;
    
        this.txtOrderTotal.Text = orderTotal.ToString("F");
        btnMoneyChange.Enabled = true;
    }
  21. Return to the form
  22. Double-click the New Order button to access its Click event and implement it as follows:
    private void btnNewOrder_Click(object sender, EventArgs e)
    {
        // If the user clicks New Order, we reset the form with the default values
        txtOrderDate.Text = DateTime.Today.ToShortDateString();
        txtOrderTime.Text = DateTime.Now.ToShortTimeString();
        txtFlavor.Text = "Vanilla";
        txtContainer.Text = "Cone";
        txtIngredient.Text = "None";
        txtScoops.Text = "1";
        txtOrderTotal.Text = "0.00";
        btnMoneyChange.Enabled = false;
    }
  23. Return to the form
  24. Double-click the Money Change button
  25. Implement the Click event as follows:
    private void btnChange_Click(object sender, EventArgs e)
    {
        // Declare a variable for the Calculation form
        Calculation dlgCalculation = new Calculation();
    
        // Transfer the current value of the Order Total text 
        // box from the main form to the other form
        dlgCalculation.txtOrderTotal.Text = this.txtOrderTotal.Text;
        // Display the other form
        dlgCalculation.ShowDialog();
    }
  26. Change the Click events of the Calculate Total  and the New Order buttons as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  27. To save the application, on the main menu, click File -> Save All
  28. Accept the default location and the name. Click Save
  29. To test the application, on the main menu, click Debug -> Start Debugging
  30. Close the form and return to Visual Studio

Exceptional Behaviors

An exception is an unusual situation that could occur in your program. As a programmer, you should anticipate any abnormal behavior that could be caused by the user entering wrong information that could otherwise lead to unpredictable results. The ability to deal with a program's eventual abnormal behavior is called exception handling. C# provides four keywords to handle an exception. At this time, we will review two of them: try and catch. Later on, one more keyword, throw, will be reviewed. In another lesson, we will introduce the last keyword, finally.

  1. Trying the normal flow: To deal with the expected behavior of a program, use the try keyword as in the following syntax:

    try {Behavior}

    The try keyword is required. It lets the compiler know that you are attempting a normal flow of your program. The actual behavior that needs to be evaluated is included between an opening curly bracket "{" and a closing curly bracket "}"�. Inside of the brackets, implement the normal flow that the program must follow, at least for this section of the code. Here is an example:
    private void button1_Click(object sender, EventArgs e)
    {
        double Number;
    
        try 
        {
    	Number = double.Parse(textBox1.Text);
    
    	textBox2.Text = (Number * 2).ToString();
        }
    
    }
  2. Catching Errors: During the flow of the program as part of the try section, if an abnormal behavior occurs, instead of letting the program crash or instead of letting the compiler send the error to the operating system, you can transfer the flow of the program to another section that can deal with it. The syntax used by this section is:

    catch {WhatToDo}

    This section always follows the try section. There must not be any code between the try's closing bracket and the catch section. The catch keyword is required and follows the try section. Combined with the try block, the syntax of an exception would be:

    try
    {
    	// Try the program flow
    }
    catch
    {
    	// Catch the exception
    }

    A program that includes a catch section would appear as follows:
    private void button1_Click(object sender, EventArgs e)
    {
        double Number;
    
        try 
        {
    	Number = double.Parse(textBox1.Text);
    
    	textBox2.Text = (Number * 2).ToString();
        }
        catch
        {
    
        }
    }
 

ApplicationApplication: Introducing Vague Exceptions

  1. On the form, double-click the Calculate button
  2. To introduce exceptions, change the event as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double priceContainer = 0.00,
               priceIngredient = 0.00,
               priceScoops = 0.00,
               orderTotal = 0.00;
        int numberOfScoops = 1;
    
        // Find out what container the customer requested
        // The price of a container depends on which one the customer selected
        if (txtContainer.Text == "Cone")
            priceContainer = 0.55;
        else if (txtContainer.Text == "Cup")
            priceContainer = 0.75;
        else
            priceContainer = 1.15;
    
        // If the customer selected an ingredient, which is not "None", add $.95
        if (txtIngredient.Text != "None")
            priceIngredient = 0.95;
    
        try
        {
            // Get the number of scoops
            numberOfScoops = int.Parse(this.txtScoops.Text);
    
            if (numberOfScoops == 2)
                priceScoops = 2.55;
            else if (numberOfScoops == 3)
                priceScoops = 3.25;
            else
                priceScoops = 1.85;
        }
        catch
        {
     
        }
    
        // Make sure the user selected a flavor, 
        // otherwise, there is no reason to process an order
        if (txtFlavor.Text != "")
            orderTotal = priceScoops + priceContainer + priceIngredient;
    
        txtOrderTotal.Text = orderTotal.ToString("F");
        btnMoneyChange.Enabled = true;
    }
  3. Execute the application
  4. In the Scoops text box, type One and click Calculate
  5. Return to your programming environment

Exceptions and Custom Messages

As mentioned already, if an error occurs when processing the program in the try section, the compiler transfers the processing to the next catch section. You can then use the catch section to deal with the error. At a minimum, you can display a message to inform the user. Here is an example:

private void button1_Click(object sender, EventArgs e)
{
        double Number;

        try 
       {
	Number = double.Parse(textBox1.Text);

	textBox2.Text = (Number * 2).ToString();
        }
        catch
        {
	MessageBox.Show("Invalid Number");
        }
}
Custom Message

Of course, your message may not be particularly clear but this time, the program will not crash. In the next sections, we will learn better ways of dealing with the errors and the messages.

ApplicationApplication: Displaying Custom Messages

  1. To display custom messages to the user, change the code of the event as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double priceContainer = 0.00,
               priceIngredient = 0.00,
               priceScoops = 0.00,
               orderTotal = 0.00;
        int numberOfScoops = 1;
    
        // Find out what container the customer requested
        // The price of a container depends on which one the customer selected
        if (txtContainer.Text == "Cone")
            priceContainer = 0.55;
        else if (txtContainer.Text == "Cup")
            priceContainer = 0.75;
        else
            priceContainer = 1.15;
    
        // If the customer selected an ingredient, which is not "None", add $.95
        if (txtIngredient.Text != "None")
            priceIngredient = 0.95;
    
        try
        {
            // Get the number of scoops
            numberOfScoops = int.Parse(this.txtScoops.Text);
    
            if (numberOfScoops == 2)
                priceScoops = 2.55;
            else if (numberOfScoops == 3)
                priceScoops = 3.25;
            else
                priceScoops = 1.85;
        }
        catch
        {
            MessageBox.Show("The value you entered for the scoops is not valid" +
                            "\nOnly natural numbers such as 1, 2, or 3 are allowed" +
                            "\nPlease try again", "Clarksville Ice Cream",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    
        // Make sure the user selected a flavor, 
        // otherwise, there is no reason to process an order
        if (txtFlavor.Text != "")
            orderTotal = priceScoops + priceContainer + priceIngredient;
    
        txtOrderTotal.Text = orderTotal.ToString("F");
        btnMoneyChange.Enabled = true;
    }
  2. Test the application with valid and invalid values. Here is an example:

    Clarksville Ice Cream

  3. Close the form and return to your programming environment

Exceptions in the .NET Framework

 

The Exception Class

In traditionally-oriented error dealing languages such as C/C++ or Object Pascal, you could create any exception of your choice, including numeric or strings. To customize exception handling, you could also create your own class(es). Most libraries such as Borland's VCL and Microsoft's MFC also shipped with their own classes to handle exceptions. Event the Win32 library provides its type of mechanism to face errors. To support exception handling, the .NET Framework provides a special class called Exception. Once the compiler encounters an error, the Exception class allows you to identify the type of error and take an appropriate action.

Normally, Exception mostly serves as the general class of exceptions. Anticipating various types of problems that can occur in a program, Microsoft derived various classes from Exception to make this issue friendlier. As a result, almost any type of exception you may encounter already has a class created to deal with it. Therefore, when your program faces an exception, you can easily identify the type of error. There are so many exception classes that we cannot study or review them all. The solution we will use is to introduce or review a class when we meet its type of error.

The Exception's Message

In exception handling, errors are dealt with in the catch section. To do this, use catch as if it were a method. This means that, on the right side of catch, opening a parenthesis, declare a variable of the type of exception you want to deal with. By default, an exception is first of type Exception. Based on this, a typical formula to implement exception handling is:

try
{
	// Process the normal flow of the program here
}
catch(Exception e)
{
	// Deal with the exception here
}

When an exception occurs in the try section, code compilation is transferred to the catch section. If you declare the exception as an Exception type, this class will identify the error. One of the properties of the Exception class is called Message. This property contains a string that describes the type of error that occurred. You can then use this Exception.Message property to display an error message if you want. Here is an example:

private void button1_Click(object sender, EventArgs e)
{
        double Number;

        try
        {
                Number = double.Parse(textBox1.Text);

                textBox2.Text = (Number * 2).ToString();
        }
        catch(FormatException ex)
        {
                MessageBox.Show(ex.Message);
        }
}
An exception using the Exception.Message message
 

Custom Error Messages

As you can see, one of the strengths of the Exception.Message property is that it gives you a good indication of the type of problem that occurred. Sometimes, the message provided by the Exception class may not appear explicit enough. In fact, you may not want to show it to the user since, as in this case, the user may not understand what the expression "correct format" in this context means and why it is being used. As an alternative, you can create your own message and display it to the user. Here is an example:

private void button1_Click(object sender, EventArgs e)
{
	double Number;

	try 
	{
		Number = double.Parse(textBox1.Text);

		textBox2.Text = (Number * 2).ToString();
	}
	catch(Exception Ex)
	{
		MessageBox.Show("The operation could not be carried because " +
				"the number you typed is not valid");
	}
}
An exception with a custom message

You can also combine the Exception.Message message and your own message:

private void button1_Click(object sender, EventArgs e)
{
	double Number;

	try 
	{
		Number = double.Parse(textBox1.Text);

		textBox2.Text = (Number * 2).ToString();
	}
	catch(Exception ex)
	{
		MessageBox.Show(ex.Message +
                                "\nThe operation could not be carried because " +
				"the number you typed is not valid");
	}
}

  

A Review of .NET Exception Classes

 

Introduction

The .NET Framework provides various classes to handle almost any type of exception you can think of. There are so many of these classes that we can only mention the few that we will regularly use in our application.

There are two main ways you can use one of the classes of the .NET Framework. If you know for sure that a particular exception will be produced, pass its name to a catch() clause. You don't have to name the argument. Then, in the catch() section, display a custom message. The second option you have consists of using the throw keyword. We will study it later.

From now on, we will try to always indicate the type of exception that could be thrown if something goes wrong in a program.

The Format Exception

Everything the user types into an application using the keyboard is primarily a string and you must convert it to the appropriate type before using it. When you request a specific type of value from the user, after the user has typed it and you decide to convert it to the appropriate type, if your conversion fails, the program produces (we will use he word "throw") an error. The error is of from the FormatException class.

Here is a program that deals with a FormatException exception:

private void button1_Click(object sender, System.EventArgs e)
{
	double Number;

	try 
	{
		Number = double.Parse(textBox1.Text);

		textBox2.Text = (Number * 2).ToString();
	}
	catch(FormatException)
	{
		MessageBox.Show("You typed an invalid number");
	}
}
The FormatException exception
 

ApplicationApplication: Using the FormatException Class

  1. Change the Click event of the Calculate button as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double priceContainer = 0.00,
               priceIngredient = 0.00,
               priceScoops = 0.00,
               orderTotal = 0.00;
        int numberOfScoops = 1;
    
        // Find out what container the customer requested
        // The price of a container depends on which one the customer selected
        if (txtContainer.Text == "Cone")
            priceContainer = 0.55;
        else if (txtContainer.Text == "Cup")
            priceContainer = 0.75;
        else
            priceContainer = 1.15;
    
        // If the customer selected an ingredient, which is not "None", add $.95
        if (txtIngredient.Text != "None")
            priceIngredient = 0.95;
    
        try
        {
            // Get the number of scoops
            numberOfScoops = int.Parse(this.txtScoops.Text);
    
            if (numberOfScoops == 2)
                priceScoops = 2.55;
            else if (numberOfScoops == 3)
                priceScoops = 3.25;
            else
                priceScoops = 1.85;
        }
        catch (FormatException)
        {
            MessageBox.Show("The value you entered for the scoops is not valid" +
                            "\nOnly natural numbers such as 1, 2, or 3 are allowed" +
                            "\nPlease try again", "Clarksville Ice Cream",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    
        // Make sure the user selected a flavor, 
        // otherwise, there is no reason to process an order
        if (txtFlavor.Text != "")
            orderTotal = priceScoops + priceContainer + priceIngredient;
    
        txtOrderTotal.Text = orderTotal.ToString("F");
        btnMoneyChange.Enabled = true;
    }
  2. In the Solution Explorer, right-click Calculation.cs and View Code
  3. Change the code of the Calculate button as follows:
    private void btnCalculate_Click(object sender, EventArgs e)
    {
        double totalOrder,
               amountTended = 0.00,
               difference;
    
        // Get the value of the total order. Actually, this value 
        // will be provided by the main form
        totalOrder = double.Parse(this.txtOrderTotal.Text);
    
        try
        {
            // The amount tended will be entered by the user
            amountTended = double.Parse(this.txtAmountTended.Text);
        }
        catch (FormatException)
        {
            MessageBox.Show("The amount you entered is not " +
                     "valid - Please try again!");
        }
    
        // Calculate the difference of both values, assuming 
        // that the amount tended is higher
        difference = amountTended - totalOrder;
    
        // Display the result in the Difference text box
        txtDifference.Text = difference.ToString("F");
    }
  4. Execute the application
  5. Return to your programming environment
  6. Close Microsoft Visual Studio. If you are asked whether you want to save the project, click Yes

The Overflow Exception

A computer application receives, processes, and produces values on a regular basis as the program is running. To better manage these values, as we saw when studying variables and data types in Lesson 2, the compiler uses appropriate amounts of space to store its values. It is not unusual that either you the programmer or a user of your application provides an value that is beyond the allowed range based on the data type. For example, we saw that a byte uses 8 bits to store a value and a combination of 8 bits can store a number no more than 255. If you provide a value higher than 255 to be stored in a byte, you get an error. Consider the following program:

private void button1_Click(object sender, System.EventArgs e)
{
	byte NumberOfPages;

	NumberOfPages = byte.Parse(this.textBox1.Text);

	this.textBox2.Text = NumberOfPages.ToString();
}

When a value beyond the allowable range is asked to be stored in memory, the compiler produces (the verb is "throws" as we will learn soon) an error of the OverflowException class. Here is an example of running the program with a bad number:

As with the other errors, when this exception is thrown, you should take appropriate action.

The Argument Out of Range Exception

Once again, we know that a value is passed to the Parse() method of its data type for analysis. For a primitive data type, the Parse() method scans the string and if the string cannot be converted into a valid character or number, the compiler usually throws a FormatException exception as we saw above. Other classes such as DateTime also use a Parse() method to scan the value submitted to it. For example, if you request a date value from the user, the DateTime.Parse() method scans the string to validate it. In US English, Parse() expects the user to type a string in the form m/d/yy or mm/dd/yy or mm/dd/yyyy. Consider the following program:

private void button1_Click(object sender, System.EventArgs e)
{
	DateTime DateHired;

	DateHired = DateTime.Parse(this.textBox1.Text);

	this.textBox2.Text = DateHired.ToString();
}
Exception

If the user types a value that cannot be converted into a valid date, the compiler throws an ArgumentOutOfRangeException exception. Here is an example of running the above program with an invalid date:

Exception

One way you can avoid this is to guide the user but still take appropriate actions, just in case this error is thrown.

The Divide by Zero Exception

Division by zero is an operation to always avoid. It is so important that it is one of the most fundamental exceptions of the computer. It is addressed at the core level even by the Intel and AMD processors. It is also addressed by the operating systems at their level. It is also addressed by most, if not all, compilers. It is also addressed by most, if not, all libraries. This means that this exception is never welcomed anywhere. The .NET Framework also provides it own class to face this operation.

If an attempt to divide a value by 0, the compiler throws a DivideByZeroException exception. We will see an example later.

Techniques of Using Exceptions

 

Throwing an Exception

As mentioned above, the Exception class is equipped with a Message property that carried a message for the error that occurred. We also mentioned that the message of this property may not be particularly useful to a user. Fortunately, you can create your own message and pass it to the Exception. To be able to receive custom messages, the Exception class provides the following constructor:

public Exception(string message);

To use it, in the section that you are anticipating the error, type the throw keyword followed by a new instance of the Exception class using the constructor that takes a string. Here is an example:

private void button1_Click(object sender, System.EventArgs e)
{
        double Operand1, Operand2;
        double Result = 0.00;
        string Operator;
    
        try 
        {
	Operand1 = double.Parse(this.txtNumber1.Text);
	Operator = this.txtOperator.Text;
	Operand2 = double.Parse(this.txtNumber2.Text);

	if( Operator != "+" && Operator != "-" && Operator != "*" && Operator != "/" )
		throw new Exception(Operator);

	switch(Operator)
	{
	case "+":
		Result = Operand1 + Operand2;
		break;
	case "-":
		Result = Operand1 - Operand2;
		break;
	case "*":
		Result = Operand1 * Operand2;
		break;
	case "/":
		Result = Operand1 / Operand2;
		break;
	default:
		MessageBox.Show("Bad Operation");
		break;
	}

	this.txtResult.Text = Result.ToString();
        }
        catch(Exception ex)
        {
	MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
        }
}

Calculator 1: Exception Handling

 

Catching Various Exceptions

In the above examples, when we anticipated some type of problem, we instructed the compiler to use our default catch section. We left it up to the compiler to find out when there was a problem and we provided a catch section to deal with it. A method with numerous or complex operations and requests can also produce different types of errors. With such a type of program, you should be able to face different problems and deal with them individually, each by its own kind. To do this, you can create different catch sections, each made for a particular error. The formula used would be:

try {
	// Code to Try
}
catch(Arg1)
{
	// One Exception
}
catch(Arg2)
{
	// Another Exception
}

The compiler would proceed in a top-down:

  1. Following the normal flow of the program, the compiler enters the try block
  2. If no exception occurs in the try block, the rest of the try block is executed
    If an exception occurs in the try block, the compiler registers the type of error that occurred. If there is a throw line, the compiler registers it also:
    1. The compiler gets out of the try section
    2. The compiler examines the first catch. If the first catch matches the thrown error, that catch executes and the exception handling routine may seize. If the first catch doesn’t match the thrown error, the compiler proceeds with the next catch
    3. The compiler checks the next match, if any and proceeds as in the first match. This continues until the compiler finds a catch that matches the thrown error
    4. If one of the catches matches the thrown error, its body executes. If no catch matches the thrown error, the compiler calls the Exception class and uses the default message

Multiple catches are written if or when a try block is expected to throw different types of errors. For example, in our calculator, we want to consider only the addition, the subtraction, the multiplication, and the division. It is also likely that the user may type one or two invalid numbers. This leads us to know that our program can produce at least two types of errors at this time. Based on this, we can address them using two catch clauses as follows:

private void button1_Click(object sender, System.EventArgs e)
{
        double Operand1, Operand2;
        double Result = 0.00;
        string Operator;

        try 
        {
	Operand1 = double.Parse(this.txtNumber1.Text);
	Operator = this.txtOperator.Text;
	Operand2 = double.Parse(this.txtNumber2.Text);

	if( Operator != "+" && Operator != "-" && Operator != "*" && Operator != "/" )
		throw new Exception(Operator);

	switch(Operator)
	{
	case "+":
		Result = Operand1 + Operand2;
		break;
	case "-":
		Result = Operand1 - Operand2;
		break;
	case "*":
		Result = Operand1 * Operand2;
		break;
	case "/":
		Result = Operand1 / Operand2;
		break;
	default:
		MessageBox.Show("Bad Operation");
		break;
	}

	this.txtResult.Text = Result.ToString();
        }
        catch(FormatException)
        {
	MessageBox.Show("You type an invalid number. Please correct it");
        }
        catch(Exception ex)
        {
	MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
        }
}

Catching multiple exceptions

This program works fine as long as the user types two valid numbers and a valid arithmetic operator. Anything else, such an invalid number or an unexpected operator would cause an error to be thrown:

Exception
Exception

Obviously various bad things could happen when this program is running. Imagine that the user wants to perform a division. You need to tell the compiler what to do if the user enters the denominator as 0 (or 0.00). If this happens, one of the options you should consider is to display a message and get out. Fortunately, the .NET Framework provides the DivideByZeroException class to deal with an exception caused by division by zero. As done with the message passed to the Exception class, you can compose your own message and pass it to the DivideByZeroException(string message) constructor.

Exception is the parent of all exception classes. This corresponds to the three periods of a C++' catch(...) block. Therefore, if you write various catch blocks, the one that takes the Exception as argument should be the last.

Here is an example that catches two types of exceptions:

private void button1_Click(object sender, System.EventArgs e)
{
        double Operand1, Operand2;
        double Result = 0.00;
        string Operator;

        try 
       {
	Operand1 = double.Parse(this.txtNumber1.Text);
	Operator = this.txtOperator.Text;
	Operand2 = double.Parse(this.txtNumber2.Text);

	if( Operator != "+" && Operator != "-" && Operator != "*" && Operator != "/" )
		throw new Exception(Operator);

	switch(Operator)
	{
	case "+":
	        Result = Operand1 + Operand2;
	        break;
	case "-":
	        Result = Operand1 - Operand2;
	        break;
	case "*":
	        Result = Operand1 * Operand2;
	        break;
	case "/":
	        if( Operand2 == 0 )
		throw new DivideByZeroException("Division by zero is not allowed");
	        Result = Operand1 / Operand2;
	        break;
	default:
	        MessageBox.Show("Bad Operation");
	        break;
	}

	this.txtResult.Text = Result.ToString();
        }
        catch(FormatException)
        {
	MessageBox.Show("You type an invalid number. Please correct it");
        }
        catch(DivideByZeroException ex)
        {
	MessageBox.Show(ex.Message);
        }
        catch(Exception ex)
        {
	MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
        }
}

Exceptions Nesting

The calculator simulator we have studied so far performs a division as one of its assignments. We learned that, in order to perform any operation, the compiler must first make sure that the user has entered a valid operator. Provided the operator is one of those we are expecting, we also must make sure that the user typed valid numbers. Even if these two criteria are met, it was possible that the user enter 0 for the denominator. The block that is used to check for a non-zero denominator depends on the exception that validates the operators. The exception that could result from a zero denominator depends on the user first entering a valid number for the denominator.

You can create an exception inside of another. This is referred to as nesting an exception. This is done by applying the same techniques we used to nest conditional statements. This means that you can write an exception that depends on, and is subject to, another exception. To nest an exception, write a try block in the body of the parent exception. The nested try block must be followed by its own catch(es) clause. To effectively handle the exception, make sure you include an appropriate throw in the try block. Here is an example:

private void button1_Click(object sender, System.EventArgs e)
{
        double Operand1, Operand2;
        double Result = 0.00;
        string Operator;

        try 
        {
	Operand1 = double.Parse(this.txtNumber1.Text);
	Operator = this.txtOperator.Text;
	Operand2 = double.Parse(this.txtNumber2.Text);

	if( Operator != "+" && Operator != "-" && Operator != "*" && Operator != "/" )
		throw new Exception(Operator);

	switch(Operator)
	{
	case "+":
		Result = Operand1 + Operand2;
		this.txtResult.Text = Result.ToString();
		break;
	case "-":
		Result = Operand1 - Operand2;
		this.txtResult.Text = Result.ToString();
		break;
	case "*":
		Result = Operand1 * Operand2;
		this.txtResult.Text = Result.ToString();
		break;
	case "/":
	        try 
	       {
		if( Operand2 == 0 )
			throw new DivideByZeroException("Division by zero is not allowed");
		Result = Operand1 / Operand2;
		this.txtResult.Text = Result.ToString();
	        }
	        catch(DivideByZeroException ex)
	        {
		MessageBox.Show(ex.Message);
	        }
	        break;
	default:
	        MessageBox.Show("Bad Operation");
	        break;
               }
        }
        catch(FormatException)
        {
	MessageBox.Show("You type an invalid number. Please correct it");
        }
        catch(Exception ex)
        {
	MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
        }
}

Exceptions and Methods

One of the most effective techniques used to deal with code is to isolate assignments. We have learned this when studying methods of classes. For example, the switch statement that was performing the operations in the "normal"� version of our program can be written as follows:

private double Calculation(double Value1, double Value2, char Symbol)
{
        double Result = 0.00;

        switch(Symbol)
        {
        case '+':
	Result = Value1 + Value2;
	break;
        case '-':
	Result = Value1 - Value2;
	break;
        case '*':
	Result = Value1 * Value2;
	break;
        case '/':
	Result = Value1 / Value2;
	break;
        }

        return Result;
}

private void button1_Click(object sender, System.EventArgs e)
{
        double Operand1, Operand2;
        double Result = 0.00;
        char Operator;

        try 
        {
	Operand1 = double.Parse(this.txtNumber1.Text);
	Operator = char.Parse(this.txtOperator.Text);
	Operand2 = double.Parse(this.txtNumber2.Text);

	if( (Operator != '+') &&
                    (Operator != '-') && 
	    (Operator != '*') && 
	    (Operator != '/') )
	        throw new Exception(Operator.ToString());

	if( Operator == '/' )
	        if( Operand2 == 0 )
	                throw new DivideByZeroException("Division by zero is not allowed");
	Result = Operand1 / Operand2;
	this.txtResult.Text = Result.ToString();
				
	Result = Calculation(Operand1, Operand2, Operator);
	this.txtResult.Text = Result.ToString();
        }
        catch(FormatException)
        {
	MessageBox.Show("You type an invalid number. Please correct it");
        }
        catch(DivideByZeroException ex)
        {
	MessageBox.Show(ex.Message);
        }
        catch(Exception ex)
        {
	MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
        }
}

This is an example of running the program:

Exception

You can still use regular methods along with methods that handle exceptions. Here is an example:

private double Addition(double Value1, double Value2)
{
	double Result;
		Result = Value1 + Value2;
	return Result;
}

private double Subtraction(double Value1, double Value2)
{
	double Result;

	Result = Value1 - Value2;
	return Result;
}

private double Multiplication(double Value1, double Value2)
{
	double Result;

	Result = Value1 * Value2;
	return Result;
}

private double Division(double Value1, double Value2)
{
	double Result;

	Result = Value1 / Value2;
	return Result;
}

private void button1_Click(object sender, System.EventArgs e)
{
	double Operand1, Operand2;
	double Result = 0.00;
	char Operator;

	try 
	{
		Operand1 = double.Parse(this.txtNumber1.Text);
		Operator = char.Parse(this.txtOperator.Text);
		Operand2 = double.Parse(this.txtNumber2.Text);

		if( Operator != '+' && Operator != '-' && 
			Operator != '*' && Operator != '/' )
			throw new Exception(Operator.ToString());

		if( Operator == '/' )
			if( Operand2 == 0 )
			throw new DivideByZeroException("Division by zero is not allowed");
				
		switch(Operator)
		{
			case '+':
				Result = Addition(Operand1, Operand2);
				break;
			case '-':
				Result = Subtraction(Operand1, Operand2);
				break;
			case '*':
				Result = Multiplication(Operand1, Operand2);
				break;
			case '/':
				Result = Division(Operand1, Operand2);
				break;
		}

		this.txtResult.Text = Result.ToString();
	}
	catch(FormatException)
	{
		MessageBox.Show("You type an invalid number. Please correct it");
	}
	catch(DivideByZeroException ex)
	{
		MessageBox.Show(ex.Message);
	}
	catch(Exception ex)
	{
		MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
	}
}

As done in Main(), any method of a program can take care of its own exceptions that would occur in its body. Isolating assignments and handing them to methods is an important matter in the area of application programming. Consider the following Division method:

private double Addition(double Value1, double Value2)
{
	double Result;

	Result = Value1 + Value2;
	return Result;
}

private double Subtraction(double Value1, double Value2)
{
	double Result;

	Result = Value1 - Value2;
	return Result;
}

private double Multiplication(double Value1, double Value2)
{
	double Result;

	Result = Value1 * Value2;
	return Result;
}

private double Division(double Value1, double Value2)
{
	double Result;

	try 
	{
		if( Value2 == 0 )
			throw new DivideByZeroException("Division by zero is not allowed");
				
		Result = Value1 / Value2;
		return Result;
	}
	catch(DivideByZeroException ex)
	{
		MessageBox.Show(ex.Message);
	}

	return 0.00;
}

private void button1_Click(object sender, System.EventArgs e)
{
	double Operand1, Operand2;
	double Result = 0.00;
	char Operator;

	try 
	{
		Operand1 = double.Parse(this.txtNumber1.Text);
		Operator = char.Parse(this.txtOperator.Text);
		Operand2 = double.Parse(this.txtNumber2.Text);

		if( Operator != '+' && Operator != '-' && 
			Operator != '*' && Operator != '/' )
			throw new Exception(Operator.ToString());

		switch(Operator)
		{
			case '+':
				Result = Addition(Operand1, Operand2);
				break;
			case '-':
				Result = Subtraction(Operand1, Operand2);
				break;
			case '*':
				Result = Multiplication(Operand1, Operand2);
				break;
			case '/':
				Result = Division(Operand1, Operand2);
				break;
		}

		this.txtResult.Text = Result.ToString();
	}
	catch(FormatException)
	{
		MessageBox.Show("You type an invalid number. Please correct it");
	}
	catch(Exception ex)
	{
		MessageBox.Show("Operation Error: " + ex.Message + " is not a valid operator");
	}
}

One of the ways you can use methods in exception routines is to have a central method that receives variables, and sends them to an external method. The external method tests the value of a variable. If an exception occurs, the external method displays or sends a throw. This throw can be picked up by the method that sent the error.

 

Home Copyright © 2010-2014, FunctionX