Home

Introduction to Exception Handling

 

Introduction to Exceptions

 

An 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.

Practical LearningPractical Learning: Introducing Exception Handling

  1. Start a new Windows Application named GeorgetownCleaningServices1
  2. Design the form as follows:
     
    Georgetown Cleaning Services - Cleaning Order Processing
    Control Name Text Additional Properties
    Form     Size: 378, 408
    Label   Customer Name:  
    TextBox txtCustomerName1    
    Label   mm  
    Label   dd  
    Label   yyyy  
    Label   Order Date:  
    TextBox txtMM 1  
    TextBox txtDD 1  
    TextBox txtYYYY 2000  
    Label   Item Types  
    Label   Qty  
    Label   Unit Price  
    Label   Sub-Total  
    Label   Shirts  
    TextBox txtQtyShirts 0  
    TextBox txtUnitPriceShirts 1.15  
    TextBox txtSubTotalShirts 0.00  
    Label   Pants  
    TextBox txtQtyPants 0  
    TextBox txtUnitPricePants 1.95  
    TextBox txtSubTotalPants 0.00  
    Label   Other  
    TextBox txtQtyOther 0  
    TextBox txtUnitPriceOther 3.50  
    TextBox txtSubTotalOther 0.00  
    Button btnProcess Process  
    Label   Customer Name:  
    TextBox txtCustomerName2    
    Label   Order date:  
    TextBox txtOrderDate    
    Label   Tax Rate:  
    TextBox txtTaxRate 5.75  
    Label   %  
    Button btnTax Tax  
    Label   Total Order:  
    TextBox txtTotalOrder 0.00  
    Label   Tax Amount:  
    TextBox txtTaxAmount 0.00  
    Label   Net Price:  
    TextBox txtNetPrice 0.00  
    Label   Amount Tended:  
    TextBox txtAmountTended 0.00  
    Button btnDifference Diff  
    Label   Difference:  
    TextBox txtDifference 0.00  
  3. To arrange the tab sequence, on the main menu, click View -> Tab Order
  4. On the form, click only the following controls whose squares have a white background, in the indicated order:
     
    Georgetown Cleaning Services - Tab Order
  5. Press Esc
  6. Right-click the form and click View Code
  7. Declare a few variables as follows:
     
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace GeorgetownCleaningServices1
    {
        public partial class Form1 : Form
        {
            // Order Information
            string CustomerName;
            string mm, dd, yyyy;
    
            // Quantities of items
            uint NumberOfShirts;
            uint NumberOfPants;
            uint NumberOfOther;
    
            // Price of items
            decimal PriceOneShirt, PriceAPairOfPants, PriceOther;
    
            // Each of these sub totals will be used for cleaning items
            decimal SubTotalShirts, SubTotalPants, SubTotalOther;
    
            // Values used to process an order
            decimal TaxRate;
            decimal TotalOrder, TaxAmount, SalesTotal;
    
            public Form1()
            {
                InitializeComponent();
            }
        }
    }
  8. Return to the form
  9. To process an order, double-click the Process button and implement its event as follows:
     
    private void btnProcess_Click(object sender, EventArgs e)
    {
                if (this.btnProcess.Text == "Process")
                {
                    this.Height = 408;
                    this.btnProcess.Text = "Reset";
                }
                else
                {
                    this.Height = 232;
                    this.txtCustomerName1.Text = "";
                    this.txtMM.Text = "1";
                    this.txtDD.Text = "1";
                    this.txtYYYY.Text = "2000";
                    this.txtQtyShirts.Text = "0";
                    this.txtQtyPants.Text = "0";
                    this.txtQtyOther.Text = "0";
                    this.txtSubTotalShirts.Text = "0.00";
                    this.txtSubTotalPants.Text = "0.00";
                    this.txtSubTotalOther.Text = "0.00";
    
                    this.btnProcess.Text = "Process";
                }
    
                // Request order information from the user
                CustomerName = this.txtCustomerName1.Text;
                mm = this.txtMM.Text;
                dd = this.txtDD.Text;
                yyyy = this.txtYYYY.Text;
    
                // Request the quantity of each category of items
                // Number of Shirts
                NumberOfShirts = uint.Parse(this.txtQtyShirts.Text);
                // Number of Pants
                NumberOfPants = uint.Parse(this.txtQtyPants.Text);
                // Number of Dresses
                NumberOfOther = uint.Parse(this.txtQtyOther.Text);
    
                // Unit Prices of items
                PriceOneShirt = decimal.Parse(this.txtUnitPriceShirts.Text);
                PriceAPairOfPants = decimal.Parse(this.txtUnitPricePants.Text);
                PriceOther = decimal.Parse(this.txtUnitPriceOther.Text);
    
                // Perform the necessary calculations
                SubTotalShirts = NumberOfShirts * PriceOneShirt;
                SubTotalPants = NumberOfPants * PriceAPairOfPants;
                SubTotalOther = NumberOfOther * PriceOther;
    
                this.txtSubTotalShirts.Text = SubTotalShirts.ToString();
                this.txtSubTotalPants.Text = SubTotalPants.ToString();
                this.txtSubTotalOther.Text = SubTotalOther.ToString();
    
                // Calculate the "temporary" total of the order
                TotalOrder = SubTotalShirts + SubTotalPants + SubTotalOther;
    
                // Display the receipt
                this.txtCustomerName2.Text = CustomerName;
                this.txtOrderDate.Text = mm + "/" + dd + "/" + yyyy;
                this.txtTotalOrder.Text = TotalOrder.ToString();
    }
  10. Return to the form
  11. Double-click the Tax button and implement its event as follows:
     
    private void btnTax_Click(object sender, EventArgs e)
    {
                // Get the tax rate
                TaxRate = decimal.Parse(this.txtTaxRate.Text) / 100;
    
                // Calculate the tax amount using a constant rate
                TaxAmount = TotalOrder * TaxRate;
                // Add the tax amount to the total order
                SalesTotal = TotalOrder + TaxAmount;
    
                this.txtTaxAmount.Text = TaxAmount.ToString();
                this.txtNetPrice.Text = SalesTotal.ToString();
    }
  12. Return to the form
  13. Double-click the Diff button and implement its event as follows:
     
    private void btnDifference_Click(object sender, EventArgs e)
    {
                decimal AmountTended= 0.00M, Difference= 0.00M;
    
                // Request money for the order
                AmountTended = decimal.Parse(this.txtAmountTended.Text);
    
                // Calculate the difference owed to the customer
                // or that the customer still owes to the store
                Difference = AmountTended - SalesTotal;
    
                this.txtDifference.Text = Difference.ToString();
    }
  14. Return to the form
  15. Resize the form to appear as follows:
     
    Georgetown Cleaning Services - Shrunk Form
  16. To execute the application, on the Standard toolbar, click the Start Without Debugging button
     
    Georgetown Cleaning Services
    Georgetown Cleaning Services
  17. Close the form and return to your programming environment
  18. Execute the application again. This time, type a letter such as d for the quantity of shirts and click Process
     
    Georgetown Cleaning Services - Error
  19. Click Quit and close the form to return to your programming environment

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
           {
    
           }
    }

 

Practical LearningPractical Learning: Introducing Vague Exceptions

  1. To introduce exceptions, access the form's code and change the events of the buttons as follows:
     
    private void btnProcess_Click(object sender, EventArgs e)
    {
                if (this.btnProcess.Text == "Process")
                {
                    this.Height = 408;
                    this.btnProcess.Text = "Reset";
                }
                else
                {
                    this.Height = 232;
                    this.txtCustomerName1.Text = "";
                    this.txtMM.Text = "1";
                    this.txtDD.Text = "1";
                    this.txtYYYY.Text = "2000";
                    this.txtQtyShirts.Text = "0";
                    this.txtQtyPants.Text = "0";
                    this.txtQtyOther.Text = "0";
                    this.txtSubTotalShirts.Text = "0.00";
                    this.txtSubTotalPants.Text = "0.00";
                    this.txtSubTotalOther.Text = "0.00";
    
                    this.btnProcess.Text = "Process";
                }
    
                // Request order information from the user
                CustomerName = this.txtCustomerName1.Text;
                mm = this.txtMM.Text;
                dd = this.txtDD.Text;
                yyyy = this.txtYYYY.Text;
    
                // Request the quantity of each category of items
                // Number of Shirts
                try
                {
                    NumberOfShirts = uint.Parse(this.txtQtyShirts.Text);
                }
                catch
                {
                }
    
                // Number of Pants
                try
                {
                    NumberOfPants = uint.Parse(this.txtQtyPants.Text);
                }
                catch
                {
                }
    
                // Number of Dresses
                try
                {
                    NumberOfOther = uint.Parse(this.txtQtyOther.Text);
                }
                catch
                {
                }
    
                // Unit Prices of items
                try
                {
                    PriceOneShirt = 
    			decimal.Parse(this.txtUnitPriceShirts.Text);
                }
                catch
                {
                }
                try
                {
                    PriceAPairOfPants = 
    			decimal.Parse(this.txtUnitPricePants.Text);
                }
                catch
                {
                }
                try
                {
                    PriceOther = decimal.Parse(this.txtUnitPriceOther.Text);
                }
                catch
                {
                }
                // Perform the necessary calculations
                SubTotalShirts = NumberOfShirts * PriceOneShirt;
                SubTotalPants = NumberOfPants * PriceAPairOfPants;
                SubTotalOther = NumberOfOther * PriceOther;
    
                this.txtSubTotalShirts.Text = SubTotalShirts.ToString();
                this.txtSubTotalPants.Text = SubTotalPants.ToString();
                this.txtSubTotalOther.Text = SubTotalOther.ToString();
    
                // Calculate the "temporary" total of the order
                TotalOrder = SubTotalShirts + SubTotalPants + SubTotalOther;
    
                // Display the receipt
                this.txtCustomerName2.Text = CustomerName;
                this.txtOrderDate.Text = mm + "/" + dd + "/" + yyyy;
                this.txtTotalOrder.Text = TotalOrder.ToString();
    }
    
    private void btnTax_Click(object sender, EventArgs e)
    {
                // Get the tax rate
                try
                {
                    TaxRate = decimal.Parse(this.txtTaxRate.Text) / 100;
                }
                catch
                {
                }
    
                // Calculate the tax amount using a constant rate
                TaxAmount = TotalOrder * TaxRate;
                // Add the tax amount to the total order
                SalesTotal = TotalOrder + TaxAmount;
    
                this.txtTaxAmount.Text = TaxAmount.ToString("F");
                this.txtNetPrice.Text = SalesTotal.ToString("F");
    }
    
    private void btnDifference_Click(object sender, EventArgs e)
    {
                decimal AmountTended= 0.00M, Difference= 0.00M;
    
                // Request money for the order
                try
                {
                    AmountTended = decimal.Parse(this.txtAmountTended.Text);
                }
                catch
                {
                }
    
                // Calculate the difference owed to the customer
                // or that the customer still owes to the store
                Difference = AmountTended - SalesTotal;
    
                this.txtDifference.Text = Difference.ToString("F");
    }
  2. Execute the application. This time, type invalid values in the quantity text boxes and other text boxes where the user is supposed to enter some values
  3. Click Process
     
    Georgetown Cleaning Services
  4. 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.

Practical LearningPractical Learning: Displaying Custom Messages

  1. To display custom messages to the user, change the form's file as follows:
     
    private void btnProcess_Click(object sender, EventArgs e)
    {
               if (this.btnProcess.Text == "Process")
                {
                    this.Height = 408;
                    this.btnProcess.Text = "Reset";
                }
                else
                {
                    this.Height = 232;
                    this.txtCustomerName1.Text = "";
                    this.txtMM.Text = "1";
                    this.txtDD.Text = "1";
                    this.txtYYYY.Text = "2000";
                    this.txtQtyShirts.Text = "0";
                    this.txtQtyPants.Text = "0";
                    this.txtQtyOther.Text = "0";
                    this.txtSubTotalShirts.Text = "0.00";
                    this.txtSubTotalPants.Text = "0.00";
                    this.txtSubTotalOther.Text = "0.00";
    
                    this.btnProcess.Text = "Process";
                }
    
                // Request order information from the user
                CustomerName = this.txtCustomerName1.Text;
                mm = this.txtMM.Text;
                dd = this.txtDD.Text;
                yyyy = this.txtYYYY.Text;
    
                // Request the quantity of each category of items
                // Number of Shirts
                try
                {
                    NumberOfShirts = uint.Parse(this.txtQtyShirts.Text);
                }
                catch
                {
                    MessageBox.Show("The value you typed for the number of " +
                                    "shirts is not a valid number." +
                                    "\nPlease enter a natural number such " +
                                    "as 2 or 24 or even 248");
                }
    
                // Number of Pants
                try
                {
                    NumberOfPants = uint.Parse(this.txtQtyPants.Text);
                }
                catch
                {
                    MessageBox.Show("The value you typed for the number of " +
                                    "pair or pants is not a valid number." +
                                    "\nPlease enter a natural number such " +
                                    "as 2 or 24 or even 248");
                }
    
                // Number of Dresses
                try
                {
                    NumberOfOther = uint.Parse(this.txtQtyOther.Text);
                }
                catch
                {
                    MessageBox.Show("The value you typed for the number of " +
                                    "other items is not a valid number." +
                                    "\nPlease enter a natural number such " +
                                    "as 2 or 24 or even 248");
                }
    
                // Unit Prices of items
                try
                {
                    PriceOneShirt = decimal.Parse(this.txtUnitPriceShirts.Text);
                }
                catch
                {
                MessageBox.Show("The value you entered for the unit price " +
                                "of a shirt is not a recognizable currency " +
                                "amount.\nOnly natural or decimal numbers " +
                                "are allowed. Please consult the management " +
                                "to know the valid prices.");
                }
                try
                {
                    PriceAPairOfPants =
    			decimal.Parse(this.txtUnitPricePants.Text);
                }
                catch
                {
                MessageBox.Show("The value you entered for the unit price of " +
                                    "a pair of pants is not a recognizable " +
                                  "currency amount.\nOnly natural or decimal " +
                                  "numbers are allowed. You can consult the " +
                                    "management to find out about " +
                                    "the allowable prices.");
                }
                try
                {
                    PriceOther = decimal.Parse(this.txtUnitPriceOther.Text);
                }
                catch
                {
                    MessageBox.Show("The value you entered for the unit " +
                                "price of other items is not a valid amount." +
                                    "\nYou must enter only a natural or a " +
                                    "decimal number. For more information, " +
                                    "please consult the management to get " +
                                    "the right prices.");
                }
    
                // Perform the necessary calculations
                SubTotalShirts = NumberOfShirts * PriceOneShirt;
                SubTotalPants = NumberOfPants * PriceAPairOfPants;
                SubTotalOther = NumberOfOther * PriceOther;
    
                this.txtSubTotalShirts.Text = SubTotalShirts.ToString();
                this.txtSubTotalPants.Text = SubTotalPants.ToString();
                this.txtSubTotalOther.Text = SubTotalOther.ToString();
    
                // Calculate the "temporary" total of the order
                TotalOrder = SubTotalShirts + SubTotalPants + SubTotalOther;
    
                // Display the receipt
                this.txtCustomerName2.Text = CustomerName;
                this.txtOrderDate.Text = mm + "/" + dd + "/" + yyyy;
                this.txtTotalOrder.Text = TotalOrder.ToString();
    }
    
    private void btnTax_Click(object sender, EventArgs e)
    {
                // Get the tax rate
                try
                {
                    TaxRate = decimal.Parse(this.txtTaxRate.Text) / 100;
                }
                catch
                {
                    MessageBox.Show("The value you entered is not " +
                                    "recognized as a valid tax rate." +
                                    "\nA valid tax rate is a value " +
                                    "between 0 and 100.00" +
                                    "\nPlease try again.");
                }
    
                // Calculate the tax amount using a constant rate
                TaxAmount = TotalOrder * TaxRate;
                // Add the tax amount to the total order
                SalesTotal = TotalOrder + TaxAmount;
    
                this.txtTaxAmount.Text = TaxAmount.ToString("F");
                this.txtNetPrice.Text = SalesTotal.ToString("F");
    }
    
    private void btnDifference_Click(object sender, EventArgs e)
    {
                decimal AmountTended = 0.00M, Difference = 0.00M;
    
                // Request money for the order
                try
                {
                    AmountTended = decimal.Parse(this.txtAmountTended.Text);
                }
                catch
                {
                    MessageBox.Show("The value you entered for the amount " +
                                    "tended is not valid. Only natural or " +
                                    "decimal numbers are allowed." +
                                    "Please try again.");
                }
    
                // Calculate the difference owed to the customer
                // or that the customer still owes to the store
                Difference = AmountTended - SalesTotal;
    
                this.txtDifference.Text = Difference.ToString("F");
    }
  2. Test the application with valid and invalid values. Here is an example:
     

    Georgetown Cleaning Services

  3. Return to Notepad

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");
	}
}
 
 

Home Copyright © 2007 FunctionX, Inc.