Click here to Skip to main content
15,892,480 members
Articles / Programming Languages / C#
Article

Designing Exception Hierarchy in C#

Rate me:
Please Sign up or sign in to vote.
1.44/5 (11 votes)
26 Oct 20065 min read 49.9K   20   5
How Exception Hierarchy be designed in C#

Sample Image - Exception_CSharp.jpg

Introduction

In this article I will talk about the Exception Handling strategy in C#.

<o:p> 

There are basically 4 types of error handling strategy

  1. Each function returning a status like HRESULT / bool.
  2. Setting a global variable / structure with error information
  3. Set Jump and Long Jump
  4. Exception Handling

<o:p> 

There is no best strategy which satisfies each and every product needs. In some situations we need to mix these strategies as one single strategy does not apply. In this article I will only talk about how one should use exception strategy efficiently.

<o:p> 

Assumption: Developer has a very good knowledge of exception handling classes in .<st1:stockticker>NET

<o:p> 

Some important points:

1.      Exceptions are not necessarily errors. Whether or not an exception represents an error is determined by the application in which the exception occurred. An exception that is thrown when a file is not found may be considered an error in one scenario, but may not represent an error in another.<o:p>

2.      All exception classes should derive from the Exception base class<o:p>

3.      ApplicationException serves as the base class for all application-specific exception classes<o:p>

4.      And the most important: Avoid throwing Exceptions unnecessarily.<o:p>

<o:p> 

Refer the exception class hierarchy at the top of this article.

This hierarchy allows your application to benefit from the following: <o:p>

1.      Easier development because you can define properties and methods on your Product base application exception class that can be inherited by your other application exception classes. <o:p>

2.      New exception classes created after your application has been deployed can derive from an existing exception type within the hierarchy. Existing exception handling code that catches one of the base classes of the new exception object will catch the new exception without any modifications to the existing code, interpreting it as one of the object's base classes. <o:p>

<o:p> 

As you create your hierarchy, use the following questions to help you to decide if you need to create a new exception class:

  1. Does an exception exist for this condition?
  2. Does a particular exception need discrete handling?<o:p>
  3. Do you need specific behavior or additional information for a particular exception?

<o:p> 

Designing your Product Base Exception Class

/// <summary><o:p>

    /// Facility specifies from where the error has occurred Kept for COM error<o:p>

    /// </summary><o:p>

    public enum Facility<o:p>

    {<o:p>

        Feature1,<o:p>

        Feature2<o:p>

    }<o:p>

    <o:p>

    /// <summary><o:p>

    /// This class defines the base type for all the custom exceptions thrown across the Product. All scenario based exceptions, should derive from BaseException class<o:p>

    /// </summary><o:p>

    public class BaseException : ApplicationException<o:p>

    {<o:p>

        public BaseException(Facility facility, short errorNo) :base()<o:p>

        {<o:p>

            HResult = MakeHResult(facility,errorNo);         <o:p>

        }<o:p>

<o:p> 

        public BaseException(Facility facility, short errorNo,string message) : base(message)<o:p>

        {<o:p>

            HResult = MakeHResult(facility,errorNo);<o:p>

        }<o:p>

      <o:p>

        public BaseException(Facility facility, short errorNo, string message, Exception inner) : base(message, inner)<o:p>

        {<o:p>

            HResult = MakeHResult(facility,errorNo);<o:p>

        }<o:p>

      <o:p>

        public BaseException(Facility facility, short errorNo,string message, string context) : base(message)<o:p>

        {<o:p>

            HResult = MakeHResult(facility,errorNo);<o:p>

            this.context = context;<o:p>

        }<o:p>

      <o:p>

        public BaseException(Facility facility, short errorNo, string message, string context, Exception inner) : base(message, inner)<o:p>

        {<o:p>

            HResult = MakeHResult(facility,errorNo);<o:p>

          <o:p>

            this.context = context;<o:p>

        }<o:p>

      <o:p>

        public int ErrorCode<o:p>

        {<o:p>

            get<o:p>

            {<o:p>

                return this.HResult;<o:p>

            }<o:p>

            set<o:p>

            {<o:p>

                this.HResult = value;<o:p>

            }<o:p>

        }<o:p>

<o:p> 

        /// <summary><o:p>

        /// A property that exposes the ErrorContext. The contents of Context<o:p>

        /// will vary upon the type of the exception and the context of the exception<o:p>

        /// For e.g if the Exception pertains to a file it may hold the name of the file that<o:p>

        /// is in error. Developers are expected to provide adequate data to identify the error context in detail.<o:p>

        /// </summary><o:p>

        public string ContextData<o:p>

        {<o:p>

            get<o:p>

            {<o:p>

                return this.context;<o:p>

            }<o:p>

            set<o:p>

            {<o:p>

                this.context = value;<o:p>

            }<o:p>

        }<o:p>

<o:p> 

        /// <summary><o:p>

        /// Returns a HRESULT from the values of severity, facility and error number<o:p>

        /// </summary><o:p>

        /// <param name="severity">The severity to be used</param><o:p>

        /// <param name="facility">The facility to be used</param><o:p>

        /// <param name="errorNo">The error number </param><o:p>

        /// <returns>A HRESULT constructed from the above 3 values</returns><o:p>

        protected int MakeHResult(Facility facility, short errorNo)<o:p>

        {<o:p>

            // Make HR<o:p>

            int result = (int)1 << 31;<o:p>

            result += (int) facility << 16;<o:p>

            result += errorNo;<o:p>

          <o:p>

            return result;<o:p>

        }<o:p>

<o:p> 

        private string context;<o:p>

    }<o:p>

<o:p> 

Why error number?<o:p>

<o:p> 

Consider there are two error states, one FileNotFoundException and InvalidFilePathException. Instead of making two exception classes which encapsulate the same data, you can write an enumeration and just pass the scenarion like this:<o:p>

public enum ErrorScenario<o:p>

      {<o:p>

        FileNotFound,<o:p>

        InvalidFilePath<o:p>

}<o:p>

<o:p> 

There is a lot to write on handling COM Error in C#. The following table maps HRESULT to its comparable exception class in the .<st1:stockticker>NET Framework<o:p>

<o:p> 

<o:p> 

<o:p> 

HRESULT<o:p>

.<st1:stockticker>NET exception<o:p>

<st1:stockticker>COR_E_APPLICATION<o:p>

ApplicationException<o:p>

<st1:stockticker>COR_E_ARGUMENT or
E_INVALIDARG<o:p>

ArgumentException<o:p>

<st1:stockticker>COR_E_ARGUMENTOUTOFRANGE<o:p>

ArgumentOutOfRangeException<o:p>

<st1:stockticker>COR_E_ARITHMETIC or
ERROR_ARITHMETIC_OVERFLOW<o:p>

ArithmeticException<o:p>

<st1:stockticker>COR_E_ARRAYTYPEMISMATCH<o:p>

ArrayTypeMismatchException<o:p>

<st1:stockticker>COR_E_DIVIDEBYZERO<o:p>

DivideByZeroException<o:p>

<st1:stockticker>COR_E_FILENOTFOUND or
ERROR_<st1:stockticker>FILE_NOT_FOUND<o:p>

FileNotFoundException<o:p>

<st1:stockticker>COR_E_FORMAT<o:p>

FormatException<o:p>

<st1:stockticker>COR_E_INDEXOUTOFRANGE<o:p>

IndexOutOfRangeException<o:p>

<st1:stockticker>COR_E_INVALIDCAST or
E_NOINTERFACE<o:p>

InvalidCastException<o:p>

<st1:stockticker>COR_E_MULTICASTNOTSUPPORTED<o:p>

MulticastNotSupportedException<o:p>

<st1:stockticker>COR_E_NOTFINITENUMBER<o:p>

NotFiniteNumberException<o:p>

E_NOTIMPL<o:p>

NotImplementedException<o:p>

<st1:stockticker>COR_E_NOTSUPPORTED<o:p>

NotSupportedException<o:p>

<st1:stockticker>COR_E_NULLREFERENCE or
E_POINTER<o:p>

NullReferenceException<o:p>

<st1:stockticker>COR_E_OUTOFMEMORY or <o:p>

E_OUTOFMEMORY<o:p>

OutOfMemoryException<o:p>

<st1:stockticker>COR_E_OVERFLOW<o:p>

OverflowException<o:p>

<st1:stockticker>COR_E_PATHTOOLONG or
ERROR_FILENAME_EXCED_RANGE<o:p>

PathTooLongException<o:p>

<st1:stockticker>COR_E_SECURITY<o:p>

SecurityException<o:p>

<o:p> 

For more details, you can reach me at SumitkJain@hotmail.com <o:p>

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
India India
Sumit Jain,Software Professional.

Comments and Discussions

 
GeneralMy vote of 1 Pin
NoCodeMonkey30-Aug-09 17:46
NoCodeMonkey30-Aug-09 17:46 
GeneralDerive from Exception, not ApplicationException Pin
Kc576-May-08 6:49
Kc576-May-08 6:49 
GeneralPrepare your code Pin
Sceptic Mole5-Nov-06 2:48
Sceptic Mole5-Nov-06 2:48 
GeneralFacility Pin
Casper Leon Nielsen3-Nov-06 0:24
Casper Leon Nielsen3-Nov-06 0:24 
AnswerRe: Facility Pin
Sumit Jain5-Nov-06 19:20
Sumit Jain5-Nov-06 19:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.