6.5 Accessing Inner Exceptions

 <  Day Day Up  >  

You want to throw an exception within an object if the object encounters an exception itself.


Technique

When creating a new exception class, create an overloaded constructor that accepts an Exception object. Initialize the base class constructor by passing the exception message and the exception object passed into the constructor:

 
 class TrafficMonitorException : ApplicationException {     public TrafficMonitorException() : this(null){}     public TrafficMonitorException( Exception e )         : base("A capacity value is set incorrectly", e ){} } 

When an exception within the class is handled, throw an instance of the exception class created earlier, passing the exception that is being handled to the overloaded constructor:

 
 class TrafficMonitor {     private int limit = 0;     private int current = 8;     public override string ToString()     {         try         {             return ((decimal)current/(decimal)limit).ToString("p",null);         }         catch( Exception e )         {             throw new TrafficMonitorException( e );         }     }     public int CapacityLimit     {         get         {             return limit;         }         set         {             limit = value;         }     }     public int CurrentCapacity     {         get         {             return current;         }         set         {             current = value;         }     } } 

A client using the class that has thrown the exception can access the exception information as usual using the Message , HelpLink , and StackTrace properties. To access the information about the exception that caused the current exception, use the InnerException property. It returns a System.Exception object:

 
 class Class1 {     [STAThread]     static void Main(string[] args)     {         TrafficMonitor tm = new TrafficMonitor();         // loop until user enters a valid value         for(;;)         {             try             {                 Console.Write( "Enter traffic capacity limit: " );                 tm.CapacityLimit = Int32.Parse( Console.ReadLine() );                 // at this point a valid value has been entered                 break;             }             catch( Exception )             {                 Console.WriteLine( "You must enter a valid value" );             }         }         // loop until user enters a valid value         for(;;)         {             try             {                 Console.Write( "Enter current traffic capacity: " );                 tm.CurrentCapacity = Int32.Parse( Console.ReadLine() );                 // valid value entered, break out of loop                 break;             }             catch( Exception )             {                 Console.WriteLine( "You must enter a valid value" );             }         }         try         {             Console.WriteLine( tm.ToString() );         }         catch( Exception e )         {             for( Exception cur = e; cur.InnerException != null; cur = cur.InnerException )                 Console.WriteLine( "Exception: {0}\nInner Exception: {1}",                     cur.Message, cur.InnerException.Message );         }     } } 

Comments

Due to the hierarchical nature of classes, it is entirely possible for a class to throw a custom exception if it encounters an exception itself. However, without a mechanism in place to filter and pass exceptions down the call stack, you won't be able to access the root cause of the exception being thrown. Fortunately, you can chain exceptions by utilizing the InnerException property, which is defined in the System.Exception class.

The code listings for this recipe define a TrafficMonitor class, which allows you to set how many cars are allowed on a stretch of road. You can then set how many cars are currently on the road and call the ToString method to retrieve a string representing the current capacity relative to the limit expressed as a percentage of that limit. This percentage is computed by dividing the current capacity by the limit. Obviously, if a mistake is made and the limit is never set, a divide-by-zero exception will be thrown. The ToString method creates an exception handler for this case, and if an exception occurs, it throws a custom exception. However, unlike the last exception, which threw a custom exception, this custom exception wraps the DivideByZero exception to add information, thereby allowing anyone using the class to find the root cause that threw the exception.

Based on the complexity of an application, an exception might be thrown within a method that must then be propagated several times as methods are removed from the stack back to the original caller. This complexity could mean that several exceptions are chained together. The System.Exception class initializes the InnerException property to null so you can create a simple loop that follows the exception chain until a null value is encountered :

 
 catch( Exception e ) {     for( Exception cur = e; cur.InnerException != null; cur = cur.InnerException )         Console.WriteLine( "Exception: {0}\nInner Exception: {1}",             cur.Message, cur.InnerException.Message ); } 
 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net