Page 1 of 1

Exception Handling

#1 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 982
  • Posts: 969
  • Joined: 30-September 10

Posted 28 March 2011 - 02:15 PM

*
POPULAR

Learning C# Series

Exception Handling

Good exception handling is a feature of every good piece of software in a object oriented framework environment. It is a key aspect of building robust software that handles problems gracefully.

In this tutorial, I shall first cover the basic syntax associated with exception handling, and then I shall move on to some commonly asked questions and best practices, finishing with a few examples.

Note: All examples are written in a Console Application’s Main method unless I specify otherwise.


Why is this important to learn about?

This is important to learn about as good exception handling is key to building robust applications, and is vital in building usable class libraries. It is a key topic in C# that you must have a good handle on!

Definitions of terms used.


Structured Exception Handling – a mechanism for handling both hardware and software exceptions. It gives developers complete control exceptions.


Note: All examples were created using Visual Studio 2010, targetting the .NET Framework 4.0. We'll do our best to point out anything that might not work in older versions.

Exception Handling

It is important to make a distinction between compile time and run time when considering exceptions. Therefore, I shall first explain, in simplistic terms, the difference between these two phases:

Compile Time vs Runtime

Exceptions are really problems that occur at run time (although there are so called compiler generated exceptions, but you don’t really need to concern yourself with them as you can really just treat them the standard exceptions - so called Compiler Generated Exceptions).

So what’s the difference between compile time and runtime in .NET?

Before your programs can run, it must be compiled. This is what is happening when we ‘build’ our solutions. The C# compiler transforms your code into a Common Intermediate Language (CIL) and Metadata (.dll or .exe). The resulting .dll or .exe is called an assembly. The compiler makes various checks on the syntax and other bits and pieces, and if it finds errors, compilation stops and the errors are displayed.

This is generally the stage we are talking about when we say compile time. At this point, the program hasn’t been run. It has just been prepared for running.

Now, when we run the programs, the .NET Execution Engine (often known as the Common Language Runtime (CLR)) steps in. It converts the CIL into machine code on demand, and executes it. This is what is simplistically happening when we see our program running. Errors that occur at this stage are called run time errors. Errors like non existent files, unable to connect to database errors, corrupted data file are errors that can occur while your program is actually running, and cannot possibly be detected at compile time. These are the sort of errors that exceptions generally deal with.

If your program doesn’t compile without errors, you cannot run it.

What Is an Exception?

An exception is an anomaly in your program that occurs at runtime (while your program is executing), that you usually could not have accounted for whilst writing your software. They are indeed used for exceptional circumstances.

In .NET, a hierarchy of classes are used to represent all the different exceptions that could be thrown. The base class of this hierarchy is the Exception class, so all exception classes ultimately derive from the Exception class.

You can also define your own custom exception classes, of which too must ultimately derive from the Exception class.

Exception Base Class

As the Exception class is the base class of all exception classes in .NET, it obviously defines some common features for all exceptions. The key properties are listed below (remember that all exception classes will have these properties as they all derive from the Exception class):

.HelpLink – This has the ability to store a URL that links to a help file that documents the exception that occurred.

.Data – This property exposes a key-value collection that allows us to describe the exceptions with extra custom information of our choosing.

.Message – This is a very commonly used property. It is read-only, and describes what the exception means in plain English. It is essentially an error message. You can set it by passing in the string message into the constructor of an exception class.

.InnerException – This is a very helpful property used when debugging programs. It stores information about previous exceptions that occurred, of which caused with current exception to occur. This means that you can get right to the root cause of the exceptions to pinpoint exactly what the underlying bug is in your code.

.Source – This simply gets or sets the name of the object or assembly that threw the exception.

.StackTrace – Again, this read-only property is very useful in debugging. It is similar to the .InnerException property in a sense. However, this contains a string that lists the sequence of calls that lead to the current exception occurring.

.TargetSite – This read-only property returns a MethodBase object, which encapsulates various details about the method that threw the exception. Again, very useful when debugging.

You’ll see how to use these properties when debugging in Visual Studio in the final section…

The exception classes generally have at least 4 constructors. One default constructor, one that takes a string message as the parameter (of which is used to set the .Message property) and one that takes a string message AND an Exception derived class (which is used to set the .InnerException property, i.e the last exception that occurred).

The other constructor has the protected access modifier and takes an instance of the SerializationInfo class and an instance of the StreamingContext struct.

This final constructor is just so that the exceptions can be deserialized. Exception class should be able to be serialized and deserialized so that they can be passed across application domains and be persisted to log files; databases etc.

Handling Exceptions


I think it is best to start out with a basic example, of which I will then explain (this is written in the Main() method of a Console Application):

      
Console.WriteLine("Please enter a valid integer"); //prompt user for input

string myString = Console.ReadLine(); //read in the input

int myNumber; //make variable to hold converted input
 
try
{
     myNumber = int.Parse(myString); //TRY and parse the integer to a string
}
catch(Exception) //if an exception is thrown by the parse method...
{
     myString = String.Empty; //reset the 'myString' variable to a stable state
}

Console.ReadKey(true); //keep console open until user presses a key




Try blocks



Now, it is the try block that we are interested in first. It contains one method call; a call to the Parse method of the int type. This method can potentially throw any one of 3 exceptions:

  • ArgumentNullException – this would occur if ‘myString’ was null
  • FormatException – this would occur, for example, if ‘myString’ was not in a format that could be parsed to an integer. For example, it contained letters.
  • OverflowException – this would occur if the number entered was to large or too small for the int type to hold.



(Note, with most methods that are documented well, you can see the list of exceptions they can throw by hovering the cursor of the name of the method when you call it. In the above example, you would hover over 'Parse').


All of these exceptions could be thrown by one method! If we didn’t use exception handling with the int.Parse method, if the user entered input that couldn’t be parsed to a number for whatever reason, one of those 3 exception would be thrown, and as there are no catch blocks that can catch the exception, it would terminate the program, causing it to crash.

Therefore, to enable us to handle these exceptions so that they don’t cause our program to crash, we wrap the code that could throw the exception in a try block. It is just the try keyword followed by two curly braces.

Think of these blocks as saying, ‘try and execute this code’.

Catch-blocks

Now, we need a block that will ‘catch’ an exceptions that occur in the try block, and handle them appropriately so that the program doesn’t crash. A catch block is just what we need!

The catch block must be preceded by a try block.

Catch blocks are a very similar format to try blocks, with one notable exception :tt2:/>/>/>/> . Notice that my catch block has 'Exception' written in parentheses after the 'catch' keyword. What is that for?

That is to tell the catch block what type of exception we want it to handle. In this case, we want it to handle all exceptions that are of type Exception. However, remember from earlier that all exceptions derive from the Exception class. Therefore, all exceptions are of type Exception, meaning that that catch block is capable of catching all types of exception in the .NET environment. I will discuss the problems with this approach later…

Now, in the catch block itself we have code that ‘handles’ the exception and returns the program to a stable state. In this case, I just empty the string variable. It matters little in such a trivial example though :)/>/>/>/>.

Note that one catch block can only have a single associated try block, however, a try block can have multiple catch blocks, and please note that you don’t have to catch ALL exceptions religiously. I discuss why you shouldn’t later…

If an exception is thrown by code in the try block, execution immediately drops to the catch block, and none of the remaining code (if there is any) in the try block is executed.

Here is an extension of my previous try-catch block example. This one use two catch blocks:

try
{
     myNumber = int.Parse(myString);
}
catch (ArgumentNullException)
{
     myString = String.Empty;
     myNumber = 0;
}
catch (OverflowException)
{
     myString = String.Empty;
     myNumber = int.MaxValue;
}



In this example, we use two catch blocks; one to catch an ArgumentNullException, one to catch an OverflowException. This allows use to react differently to these different exceptions. Again, it is trivial really what goes in the catch blocks in such a simple example.

We shall see more realistic catch block implementations later on in the tutorial (in the Best Practice and Tips section).


Note that only a single catch block is executed when an exception occurs. When an exception occurs in the try block, each of the catch blocks are checked sequentially (from top to bottom) until (or if!) a catch block is found that can handle the exception.

Finally blocks

There is one more block that can accompany try blocks and catch blocks. You use a finally block to ensure certain pieces on code get executed, regardless of whether an exception occurs in the try block. This makes finally blocks perfect candidates for cleaning up resources (closing streams, closing database connections etc).

In this example, I try to open and write to a file that doesn’t exist, and I use a finally block to clean up resources and close the file stream:

//variable to hold StreamReader object
System.IO.TextReader fs = null;

//variable to hold text read from file
string fileContents = String.Empty;

try
{
     //TRY to open a stream to the file
     fs = new System.IO.StreamReader("IDontExist.txt");

     //TRY to read the contents of the file and store them in a variable
     fileContents = fs.ReadToEnd();
}
catch (Exception e) //catch all exceptions
{
     //display the message associated with the exception that has been thrown
     Console.WriteLine(e.Message); 
     //you can access any of the properties of the exception like this
}                                 
finally
{
     // Make sure that the file gets closed.
     if (fs != null) 
     {
        fs.Close();
     }
}


In this code, we try to open a stream to a file and read the contents of that file. However, as that file doesn’t exist, the first line in the try block will throw a FileNotFoundException. This will cause execution to go immediately to the catch block (without executing the ReadToEnd() method in the try block).

The catch block is configured to catch all exceptions of type Exception (i.e. all exceptions). Therefore, it catches the FileNotFoundException and displays the associated message by accessing the .Message property of the exception.

Then, we have a finally block. Only a single finally block can be associated with a single try block, and a finally must come after all catch blocks. The code in that block first checks to ensure there is actually a stream to close by checking for null, and it then closes the stream if there is a stream to close.

That one line of code in the finally block will run regardless of whether an exception was thrown in the try block or not. This is important as it means our stream will always get closed, not matter what *.

(* at this point, it is worth noting that it isn’t entirely true that a finally block is guaranteed to be executed. If the executing thread is killed via the Win32 TerminateThread function, or if the process is killed via the Win32 TerminateProcess function or .NET’s System.Environment’s FailFast method, then the finally block will not execute. However, you don’t need to worry about this as Windows should clean up your resources for you in these cases :)/>/>/>/>).

Further, you don’t actually have to have catch blocks before the finally block. You can just have what is known as a try-finally block:

//variable to hold StreamReader object
System.IO.TextReader fs = null;

//variable to hold text read from file
string fileContents = String.Empty;

try
{
     //TRY to open a stream to the file
     fs = new System.IO.StreamReader("IDontExist.txt");

     //TRY to read the contents of the file and store them in a variable
     fileContents = fs.ReadToEnd();
}
finally
{
     // Make sure that the file gets closed.
     if (fs != null) 
     {
        fs.Close();
     }
}



The above is perfectly valid code. What we are saying there is simply that we want to close the stream irrespective of any exceptions that may occur. We are guaranteeing that the stream gets closed.

However, I wouldn’t recommend using try-finally blocks very often, as what if an exception occurs in the try block? You are much better off using a try-catch-finally, as then you can handle any exceptions that occur gracefully in your catch blocks AND guarantee that code in the finally block always gets executed. The best of both worlds!

A quick note on catch blocks with no exception type

Sometimes you will see try-catch blocks that look something like this:

try 
{
      //exception prone code here
}
catch 
{ //no type specified in parentheses
      //handle any exceptions here
}


Notice that the catch block has no exception type specified in parentheses. What does this mean? This basically means that that catch block will catch all exceptions. Hang on a minute though, isn’t that what we did by using the base Exception class earlier catch (Exception) { ... }?

Here is a brief history lesson that will help clarify…

Firstly, recognize that there are technically two types of exception that can occur; CLS-Compliant and non CLS-Compliant exceptions.

CLS-Compliant exceptions are exception types that are derived from the Exception class. It is common knowledge that all exceptions must be derived from the Exception base class.

However, the .NET CLR (common language runtime) doesn’t actually enforce this rule. It will actually allow an instance of ANY type to be thrown as an exception. It is the C# language compiler itself that means we cannot throw exceptions that aren’t derived from the Exception base class in C#.

However, certain languages ALLOW programmers to throw exception types that ARE NOT derived from the Exception base class.

Exceptions that aren’t derived from the Exception base class are called Non CLS-Compliant exceptions.

However, what if we have a C# program that calls methods that are written in another language of which supports non CLS-Compliant exceptions? Surely our catch block won’t catch those exceptions because all of our catch blocks in C# catch exceptions that are derived from the Exception base class ONLY?

Well, before C# 2.0, we used the syntax above (catch block with no exception type) to ensure non CLS-Compliant exceptions were caught. Basically, what that catch is doing is literally catching EVERY possible exception; whether it be CLS-Compliant or otherwise.

Before C# 2.0, the catch block in this example:

try
{
      //exception prone code here
}
catch (Exception)
{
      //handle any exceptions here
}


would catch all exceptions that derive from the Exception base class only. However, that catch block would not catch non CLS-Compliant that could be raised from other languages that may be getting called from C#.

Remember that non CLS-Compliant aren’t possible in C#, but there are in certain other languages, so if we are calling code written in one of those languages, we need a way to catch such exceptions. Thus, we used the catch block with no exception type specified.

However, with the arrival of C# 2.0 (and all subsequent releases), the code above that catches all Exception derived exceptions, now catches all non CLS-Compliant exceptions also (with the introduction of the RuntimeWrappedException class. Basically, in version 2.0 of the CLR (and thus version 2.0 of C#), when a non–CLS-compliant exception is thrown, the CLR automatically constructs an instance of the RuntimeWrappedException class and initializes its private field to refer to the object that was actually thrown. In effect, the CLR now turns all non–CLS-compliant exceptions into CLS-compliant exceptions.).

So basically, with all versions of C# above and including version 2.0, there is no difference between the two catch blocks above. Therefore, the first ‘empty’ catch should be completely redundant in such versions!

To summarise this, here is a piece of now trivial code. In versions of C# equal to or above 2.0, the second catch block would NEVER get run. In older versions though, this structure is how developers used to deal with non CLS-Compliant exceptions separately from CLS-compliant exceptions:

try {
// Put code requiring graceful recovery and/or cleanup operations here...
}
catch (Exception e) {
// Before C# 2.0, this block catches CLS-compliant exceptions only
// Now, this block catches CLS-compliant AND non–CLS-compliant exceptions
}
catch {
// In all versions of C#, this block catches CLS- & non–CLS-compliant exceptions
} 


Throwing an Exception

There is a reserved keyword that can be used to throw/raise exceptions in our code. It is appropriately named ‘throw’.

General guidelines dictate that you should throw an exception in any of the following scenarios:

  • When the arguments passed into a method are invalid
  • When an operation on an object that has inappropriate state is attempted. In a method that reads from a file stream, if the file stream was only accepting write requests, you would throw an InvalidOperationException.
  • When a method cannot complete its job, as specified by the method’s name.


As a general rule, the throwing of exceptions should be reserved for exceptional circumstances (i.e. things
that should never happen). You generally shouldn't throw exceptions when the data the user enters is invalid, for example, as we fully expect that the user will, at some point, enter invalid data. When should aim to validate the data by other means in such scenarios.

A couple of examples to demonstrate the syntax:

throw new DivideByZeroException(“Cannot divide by zero”); //throw new exception


try
{
   int number = 9 / 0;
}
catch(DivideByZeroException)
{
   throw; //re-throw DivideByZeroException instance caught by catch block. I'll explain this later...
}




Best Practices and Tips


How much code should you put in a try block?

A common suggestion here is that you should put a little code in the try block as is possible.

A slightly better way to put this is that, where possible, only code that can throw exception should go in a try block.

However, the real answer to this question is that it depends. If you have 3 lines of code, each of which have the potential to throw the same exception, and the way that you would handle/recover from the exception is the same for each line, it is generally fine to put all 3 lines in a single try block.

If you would recover from the same exception that could be thrown by any of the 3 lines in 3 different ways, depending on the line that threw the exception, you should use 3 different try blocks. One for each line :)/>/>.

Providing the caller with the ability to avoid the an exception being thrown

It is often a good idea to give the user of an API a choice. If you have a method that throws an exception under a certain condition, give the user another method that allows them to check for that condition before calling the method that may throw the exception, and thereby avoid the exception being thrown.

Application vs Class Library Development

Your attitude to handling exceptions should be quite drastically different depending on whether you are building a class library (that other developers will use), or whether you are building an application.

If you are building a class library, here are some points to keep in mind:

1) Never catch all exceptions UNLESS you rethrow the exception that occurred from the catch block using the 'throw' keyword. If you just swallow it and don't let the callers know, you are hiding the error from them! You should generally let exceptions filter up to their code and let them decide how best to handle it.

A better alternative to catching all exceptions is often to define your own exception type (more on this later), and catch all exceptions of that type. At least then you are only catching exceptions that you throw, instead of catching every possibly exception that can be thrown (some of which could be caused by fundamental errors in your code (think NullReferenceException, and the like), and therefore need fixing, not catching).

2) Be sparing with your use of catch blocks (do not religiously catch everything with a million different catch blocks). By handling an exception in a class library, you are saying that you know exactly how to recover from it fully. Let the caller decide what to do with the exception by re-throwing it. It should be the caller’s decision. It is not up to you to decide what constitutes an error (more on this later).

3) Try not to make any heavy assumptions about what an error is. Try to let the calling code decide what constitutes an error where possible.


If your building an application, the principles outlined for use when building class libraries do still apply, but they apply in a much more loose fashion largely due to the fact that application code will be very close to the top of the call stack, thus it provides the last chance to handle any unhandled exceptions.

The average application developer has the freedom to define their own exception handling policies. The can be as aggressive as they see fit with regards to catching exceptions. They are not bound to the class library development guidelines.

In general, if you’re an application developer, bear the best practice principles in mind, but feel free to move away from them and define your own policies where appropriate and necessary.

For example, it isn’t quite so catastrophically wrong (although, you should still carefully consider the implications) to use a catch block that catches all exceptions and then doesn't re-throw the exception that occurred if your building the UI layer for an application, for example. This is because your code will likely be the last line of defense. If the exception gets past your code, it will bring down the whole program, so you can be a bit more aggressive with your exception handling to prevent that from happening. You should at least notify the user of the error though :)/>.


What to do when corrupted state is detected that cannot be recovered from?

If a method detects that state has been corrupted in a way that would mean the behavior of the program would be unpredictable from that point on (or even a security risk), you should not throw an exception.

In such a serious situation, you should call System.Environment’s FailFast() to terminate the process, and therefore the program.


Using multiple catch blocks

When using multiple catch blocks, each of which catches a different type of exception, always have the most specific exception type first. By specific, I mean most derived. All Exceptions in C# derive from the Exception base class, as we know. Thus we have a class hierarchy of exception classes. The most specific exceptions are the ones lower down the hierarchy (the most distant relatives of the Exception class). The more general exceptions are ones that are closer to the Exception class in this hierarchy.

For example, take the ArithmeticException and DivideByZeroException. They obviously both derive from the Exception class, but which one is more specific. You can probably tell by the names, but often you will have to refer to the MSDN documentation to conclusively decide.

Anyway, DivideByZeroException actually derives from ArithmeticException. It is a more specialized version of ArithmeticException, therefore it is more specific and should go before an ArithmeticException catch block:

try
{

}
catch(DivideByZeroException)
{

}
catch(ArithmeticException)
{

}


Note: That is just an example to demonstrate the point. In real code, you wouldn't catch a DivideByZeroException and the like. Instead, you would prevent the exception from ever occurring by checking for zero before you divide.

Never just swallow exceptions

When I say swallow exceptions, I mean catch them a do nothing, i.e. have a catch block with absolutely no code in. This is just masking a problem, and masking problems rather than solving them is never a good idea! At the very least, you should re-throw the exception and/or log it to a file/database that has occurred so that it can propagate further up the call stack (the call stack is the sequence of method calls that lead up to the exception) and be handled higher up.


When and how should I re-throw exceptions?

In some situations, you may want to catch one type of exception, and then immediately throw a different kind of exception that wraps the original one. You could do this to provide extra information to the caller of the method regarding what went wrong.

Also, you can simply re-throw the same exception that was just caught in the catch block. For example, we have a method with this code in it:

try
{
     //code that could throw a FileNotFoundException
}
catch(FileNotFoundException e)
{
    throw; //rethrow exception instance
}


We do this in a few situations:

1) When the current method cannot handle the exception properly. Thus, it re-throws the exception and lets another method higher up the call stack handle it properly.

2) When we want to do some processing of the exception (or perform some action using the exception, like logging it to a file for, example) or add some extra information to the exception in the current method, but we don’t want to handle it completely. We want to leave to another method higher up the call stack the job of handling the method properly.

3) To let the caller of a method know that a problem occurred. You should never just swallow exceptions, without giving the caller some indication that something went wrong (and preferably, what that ‘something’ was too!).

4) We do this in catch blocks that uses the Exception class as its ‘exception type to catch’, so the caller knows something has gone wrong.


Note that when we re-throw an exception in a catch block of type Exception, we are re-throwing the underlying exception type. So, for example, if a catch block that can catch all exceptions catches an IndexOutOfBoundsException, when we use the throw; statement, we throw the instance of the IndexOutOfBoundsException class, NOT an instance of the Exception class. Hence, calling methods will know specifically what type of exception occurred if we re-throw the exception, and so will be in a better place to handle it as a result!


(Don’t worry if you don’t quite understand this at the moment. Hopefully it will become a bit clearer in the example at the end of the tutorial :)/>/>/>/>.)

For example, we could do this:

try 
{
    //exception prone code
}
catch (IOException e) 
{
   // Add the filename to the IOException instance
   e.Data.Add("Filename", filename); //where ‘fileName’ is a variable
   throw; // re-throw the same exception object that now has additional data in it
}


In this code, we catch the IOException instance, and add some more information to it, via its .Data property. We then re-throw it so that another method higher up the call stack can handle it with the benefit of the extra information (the name of the file that caused the problem) we provided!

Further, using this technique, we can have one method handle the exception at its level, and then re-throw it so other levels in the call stack can recover and handle exception too, which allows better separation of concerns in our code.

Note: I used ‘throw;’, not ‘throw e;’ or some equivalent. ALWAYS use the first technique when re-throwing exceptions (throw on its own) as it preserves the .StackTrace property of the exception. The second way causes the .StackTrace property of the exception to be overwritten, which could make debugging your code much harder, and will give you a false impression of where the problem actually occurred.

throw e; would cause it to start a new stack trace, meaning that anyone debugging the exception will be lead to believe that the original exception was thrown in your method (as that is what the .StackTrace property will show), when actually, the ORIGINAL exception was thrown in some other method.


Plus, as a side note here, when throwing exceptions generally, do not throw base class exception types (like Exception, ApplicationException, SystemException) as they can represent any number of different exceptions (through polymorphism) and so don’t provide a clear indication as to what actually went wrong.


Good Technique for recovering and maintaining state

When you catch exceptions, you are committed to either handling them fully or re-throwing them. A well handled exception should maintain object state, i.e. it should leave objects in a nice, stable state. Preferably in the state they were in before the exception occurred! This is similar to database transactions. You want to use try...catch blocks to ensure that your program is always in a completely valid state.

You could do this by storing the current state in a variable before a try block. Then, execute the code in the try block, and if an exception occurs, catch it and return the state to what is was before the code entered the try block.

A basic example could be (this is just an example method, and isn’t written in any particular type of application :)/>/>/>/>:

public void WriteToFile(System.IO.FileStream fs, string messageToWrite)
{
      // Save the current position of the file.
      long beforeWrite = fs.Position;

      //get byte array to write to file
      byte[] bytesToWrite = Encoding.ASCII.GetBytes(messageToWrite);

      try
      {
           //try and write 
           fs.Write(bytesToWrite, 0, bytesToWrite.Length);
      }
      catch (Exception e)// Catch ALL (CLS-Compliant or otherwise, as I am using C# 4.0!) exceptions.
      { 
           // If ANYTHING goes wrong, reset the file back to a good state.
           fs.Position = beforeWrite;

           //reduce the file stream to the length that matches the current position
           fs.SetLength(fs.Position);
                
           //state has been maintained, so rethrow exception to let the caller know that a problem occured
//Recall it is okay to catch 
//all exceptions in a single catch as long as we rethrow.
           throw;

      }
}


The caller of this method passes in a file stream to use and a message to write. Now, think about this for a second. The FileStream object passed in could be in ANY state, we as the creators of the method just don’t know! The current position could be positioned write at the end of the file, at the beginning, or somewhere in the middle.

Therefore, if we don’t take exception handling measures, and the write attempt fails half way through, then our method is going to modify the state of the file stream without completing its job properly. Thus, it is going to fail, AND it is going to leave the callers file stream in a modified, potentially corrupt state of which is very likely to lead their program to break. This is very very bad! Methods should not corrupt/change state in such a way.

Happily, the solution is exception handling. We first store the current, stable position of the file stream into a variable. We then wrap the attempt to write to the file stream in a try block. If any exception occurs during the write, we restore the stream position to it’s original position, and truncate the length of the stream to correspond with that position. Thus, state is maintained and the caller is happy.

We then let the caller know that a problem has happened (instead of just hiding the problem) by re-throwing the exception that occurred. They can then write code on their side handle this exception gracefully and continue with their program’s executing with a stream that is in a stable, correct state!

This is actually a very good use of the catch block that catches all exception types!


If you're building a class library, the key thing is to allow the calling code to decide what to do with an error, and, to some extent, what an error is. Your method should not make assumptions as to what should be done with the error, it should just ensure that calling state is maintained.


Custom Exceptions

It is best practice to (when throwing exceptions) throw the most specific exception that matches what has actually gone wrong the most closely. However, sometimes there are not any built in .NET exception classes that match what has actually happened accurately enough.

In this situation, you may be better off defining your own exception class. This isn’t necessarily as straight forward as it may first sound.

The primary reason I say this is that best practice dictates that the exception is serializable so that they can be logged easily or passed between application domains.

As such, I think it would deviate slightly too far from the main focus of this tutorial to cover that here. If you need to define your own custom exception classes, have a look at these links for best practices and examples:

MSDN Guidelines

Very brief MSDN Example

More complete example


Debugging Exceptions, the Call Stack and a General Example that brings together some key topics!

In this basic example(s), I hope to introduce you to the support that Visual Studio has (I am using 2010, but support is broadly equivalent in older versions) for debugging exceptions, and I am going to try and help you understand more clearly what we mean when we say call stack and calling code.


To follow along with this brief example, ensure you have a fresh, new Console Application open. Rename your Program class to FirstCaller, now create one class called SecondCaller and another class called EndOfCallStack. Make all the classes static. Then, we are going to add two methods to the SecondCaller and EndOfCallStack classes. Ensure you have all these classes with the corresponding methods (you can put them all in the Program.cs file if you wish):


//application level code of which is calling the class
//library code
static class FirstCaller
{
     static void Main(string[] args)
     {
         //here we call Divide on the SecondCaller class...
         Console.WriteLine(SecondCaller.Divide("20", "0"));
            
         Console.ReadKey(true); //keep console open until user presses a key
     }
}
//first layer of class library code
static class SecondCaller
{
     //this method is called from Main() in the FirstCaller class
     public static int Divide(string operand1, string operand2)
     {
         //this method then converts the string values to integers, and delegates to the Divide method in the EndOfCallStack class
         return EndOfCallStack.Divide(int.Parse(operand1), int.Parse(operand2));
     }

}

//second layer of class library code
static class EndOfCallStack
{
     //this is the final call in the call stack, and it performs the calculation, and passes the answer back to
     //Divide in SecondCaller, of which then passes it back to Main() in FirstCaller of which then passed it to Console.WriteLine()
     //of which displays it on screen. This is a call stack!
     public static int Divide(int operand1, int operand2)
     {
         return operand1 / operand2;
     }
}




Make sure you read the comments above, from top to bottom. You should be able to see how we chain different method calls together. This is a very obvious and contrived call stack. Every program will have call stacks as different methods are called within it.

Now, notice how we passed “0” as the second operand into the call to the SecondCaller.Divide() method in Main(). When EndOfCallStack.Divide() is eventually called, it should raise a DivdeByZeroException.

Run the program and see what happens…

You should have seen a little window like this pop up:

Attached Image[

This means that an exception was unhandled, and thus caused our program to terminate/crash. It even displays the .Message property of the DivideByZeroException instance to help you establish what may have gone wrong!

Notice also the ‘Copy to Clipboard’ link. This is very helpful for say…getting good help on Internet forums ;)/>/>/>/>. It allows you to copy all the relevant detail regarding the exception so others can help diagnose the problem more easily!


This exception was raised in the EndOfCallStack.Divide method, but there was no catch block to catch the exception, therefore, it started to propagate up the call stack, method by method. So, what method called EndOfCallStack.Divide()?

It was SecondCaller.Divide() of course. However, there is no error handling code (try-catch) here either. Therefore, it continues to move up the call stack. Simplistically, the next and final stop is the Main method as that was the one that called SecondCaller.Divide() (although there are more methods that are called before Main() automatically behind the scenes by the runtime to get the program running but we can completely ignore these here). However, there is no exception handling code in Main() either...


Now, we are at the end of the call stack. We are back at the root/start of the program (Main()), and the exception is still unhanded, therefore it brings the whole program down!


Finding where the Exception occurred

It is obvious where the exception occurred here, but it won’t be in more complex programs that make multiple chained calls to various different methods. So, to help you debug the exception, click on the ‘View Detail’ link on the ‘Unhandled Exception’ box that appeared when you ran the program…

This window should pop up:

Attached Image

Now, click on the little inward pointing arrow/triangle next to the highlighted ‘System.DivideByZeroException’ text.

The window should now look like this:

Attached Image

This window should spark some familiarity as it displays all the values of the properties in the exception object. Remember, all those properties (.Data, .StackTrace etc) are defined in the Exception base class and are inherited down to all other Exception classes).

You can now use these properties to find exactly where and why the exception occurred.

First, look at the .StackTrace property. This essentially shows the call stack; the sequence of calls that lead to the exception. In this example, it looks like this:

Quote

at DICExceptionHandling.EndOfCallStack.Divide(Int32 operand1, Int32 operand2) in K:\Users\UserName\Documents\Visual Studio 2010\Projects\DICExceptionHandling\DICExceptionHandling\Program.cs:line 38
at DICExceptionHandling.SecondCaller.Divide(String operand1, String operand2) in K:\Users\UserName\Documents\Visual Studio 2010\Projects\DICExceptionHandling\DICExceptionHandling\Program.cs:line 25
at DICExceptionHandling.FirstCaller.Main(String[] args) in K:\Users\UserName\Documents\Visual Studio 2010\Projects\DICExceptionHandling\DICExceptionHandling\Program.cs:line 13

at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()


Now, you should read it from the bottom up. The bottom line showing the first call made. The first few calls are methods that are called automatically by the runtime to get the program up and running, as I mentioned earlier.

If you follow the stack trace up, you eventually come to a line that looks similar to this

'DICExceptionHandling.FirstCaller.Main(String[] args)'

(NOTE: DICExceptionHandling is the name of the namespace that I put all my classes in. Yours may be different!). Your file paths may be different also.


(the part of the trace that we are interested in is in italics above).

Then, from there, you can follow the sequence of method calls we made, right up until the final method call, of which was EndOfCallStack.Divide(), at which point the exception was thrown.


Take a look at the .TargetSite property also. In there (if you expand it using the little arrow to the left again) separate properties giving various pieces of information about the method in which the exception was raised. If you scroll down to the bottom, you can even see the return type, parameters etc of the offending method, of which is EndOfCallStack.Divide(), as suggested by the .StackTrace.

Further, you may wonder why the .InnerException property is null. It is null because only one exception occurred. The idea with an inner exception is that it shows the exceptions that occurred prior to the current exception happening. There aren't any in our example however.

However, when debugging, the current exception that we are seeing on screen may not be the root cause of the problem. The problem may have been caused by another exception that was thrown somewhere else, of which then triggered the occurrence of the exception we are seeing. This .InnerException property is VITAL when debugging exceptions as, without it, you may never get to the root cause of an exception.

To demonstrate this property in action, change the SecondCallerClass to this:

   
static class SecondCaller
{
     //this method is called from Main() in the FirstCaller class
     public static int Divide(string operand1, string operand2)
     {
         try
         {
             return EndOfCallStack.Divide(int.Parse(operand1), int.Parse(operand2));
         }
         catch (DivideByZeroException e)
         {
             throw new InvalidOperationException("Could not complete operation", e);
         }
     }
}


So, what is happening now is that Main() is calling SecondCaller.Divide, of which is the calling EndOfCallStack.Divide() of which then throws a DivideByZeroException. However, there is still no catch block to handle this exception in EndOfCallStack.Divide(). Therefore, the exception propagates up the call stack to SecondCaller.Divide().

Ah ha! Here there is a catch block to handle the exception now. Therefore, execution drops to the catch block. In the catch block, we wrap the DivideByZeroException in a new InvalidOperationException (by passing it in as a second parameter to the constructor). We also pass in a custom message.

Now, SecondCaller.Divide() has handled the DivideByZeroException, but it now cannot complete it’s operation as it hasn’t got a valid value back from EndOfCallStack.Divide(). Therefore, it let’s the caller know this fact by throwing a new InvalidOperationException.

This new exception propagates up to the caller (which is Main() in this example). There is still no exception handling in Main(), and so the program terminates. However, this time, it terminates with an InvalidOperationException, thus, initially, giving a slightly misleading (or at least vague) picture as to what went wrong (as, remember, the problem has actually arisen because we tried to divide by zero).

If we go into ‘View Detail’ again, and look at the .StackTrace and .TargetSite properties, they indicate that the exception occurred in SecondCaller.Divide(). Well, yes, that unhanded exception did occur in that method, but that exception was thrown only as a result of the DivideByZeroException, and is therefore not at the root of the problem. Thus, those two properties are misleading us slightly.

Enter, .InnerException…

Using .InnerException

If you look at the .InnerException property (and that should be your first stop when debugging any exception), you will see it is no longer null. It shows the "Attempted to divide by zero” message. This is can be thought of the exception that directly lead to the occurrence of the InvalidOperationException, i.e. the .InnerException of the InvalidOperationException instance.

Expand the .InnerException window by clicking the little inward pointing arrow next to ‘.InnerException’. This displays the properties of the previous exception (DivideByZeroException in this case). You can keep going down levels (we only have two levels here as only two exceptions were thrown) and thus, you can drill down to the root cause of the exception you are seeing (the exception that started all the trouble!), and you can view all the exceptions that were thrown as a direct or indirect result of that initial, root exception.

In more complex programs, your .InnerException property will likely be several layers thick. You will have to expand it multiple times to get to the root exception.

If you construct a new exception and throw it like that, it is very important that you pass in the previous exception.

If we just did this in our example (i.e. did not pass in the DivideByZeroException to the constructor):

throw new InvalidOperationException(“Cannot perform this operation”);


There would be no inner exceptions. Thus, to someone debugging their code, it would appear that the SecondCaller.Divide() method was the method that caused the original exception, and it would appear that the InvalidOperationException was the original exception. Thus, they would be spending hours pulling their hair out trying to work out why that method was throwing that exception, when actually, it wasn’t that method that caused the series of exceptions to be raisedin the first place! It was an entirely different method (namely, EndOfCallStack.Divide())!

Note that the calls to int.Parse() could also throw exceptions, so perhaps we could take that into account and do this (just change FirstCaller and SecondCaller to this):

static void Main(string[] args)
{
     //here we call Divide on the SecondCaller class...

     try
     {
          Console.WriteLine(SecondCaller.Divide("20", "0"));
     }
     catch (DivideByZeroException e)
     {
          Console.WriteLine(e.Message);
     }
     catch (FormatException e)
     {
          Console.WriteLine(e.Message);
     }
     catch (Exception e)//catch any remaining exceptions that aren’t    covered by the first two catch blocks
     {
          Console.WriteLine(e.Message);
          //we don't rethrow the exception
          //as we are at the top of our call stack
          //so rethrowing it would cause it to crash
          //program. This is analogous to application
          //code, of which usually sits close to the
          //top of the call stack. Hence why
          //application code can be more aggressive
          //with their exception handling policies
     }
            
     Console.ReadKey(true); //keep console open until user presses a key
}

static class SecondCaller
{
     //this method is called from Main() in the FirstCaller class
     public static int Divide(string operand1, string operand2)
     {
         try
         {
             return EndOfCallStack.Divide(int.Parse(operand1), int.Parse(operand2));
         }
         catch (Exception e)
         {
             //could perhaps log the exception to file here before re-throwing?
             throw;
         }
     }

}


Now, SecondCaller.Divide() will catch any exception that occurs from the int.Parse() calls or the EndOfCallStack.Divide() method. Crucially though, instead of saying ‘oh, I can handle all these exception in one block’, which would be foolish, what it does is it throws what ever exception occurs back up the call stack. Thus allowing Main() (the calling, application level code) to decide how to handle it (which just involves displaying the exception message, in this case).


Notice how our class library methods in the SecondCaller and EndOfCallStack classes always aim to throw the exception up the call stack for the calling code to catch. However, the application level, calling code is very defensive to ensure no exceptions get past.


You could perhaps log the exception to a file/database before you re-throw it. That would be a great use of this technique! You would have a log of the exception, AND the users of your class library would still have complete free will in deciding how to handle it.

Note that Main() just prints out the relevant message. You may want to be a bit more robust than that, allowing retries or whatever.


Note also that if we used throw e; instead of throw; in our SecondCaller.Divide() method, the .StackTrace and .TargetSite properties would suggest that the exception originated in that method as we would be throwing a new instance of the exception. However, by using throw;, the stack trace is preserved and we can see that the method that caused the problem was EndOfCallStack.Divide() :)/>/>/>/>.


The examples above aren't perfect examples (in reality, you wouldn't use the InvalidOperation in that example, as it just confuses things), but they are just designed to give you an insight into a few key ideas/concepts within the topic of exception handling. Topics that newcomers tend to find difficult to grasp :)/>/>/>/>

In Conclusion

Overall, the syntax around exceptions is simple. However, it is the details of when, why and how that provide the difficulty. I would advise trying to get a basic understanding of the principle of the call stack and the consequences of certain actions. After all, if you’re an application developer, it will make your application more robust. If you’re a class library developer, you’ll keep all the developers that use your library sane, which is always a plus point ;)/>/>/>/>

Here is the associated MSDN resource for you to have a look at as my tutorial is by no means exhaustive:

MSDN Documentation

See all the C# Learning Series tutorials here!

This post has been edited by CodingSup3rnatur@l-360: 24 May 2013 - 03:08 AM


Is This A Good Question/Topic? 10
  • +

Replies To: Exception Handling

#2 DivideByZero  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 238
  • View blog
  • Posts: 551
  • Joined: 02-December 10

Posted 04 April 2011 - 08:20 AM

I wish you did this tutorial a few weeks ago when I was doing an assignment with C# :)
Great tutorial :gunsmilie:
Was This Post Helpful? 1
  • +
  • -

#3 peace_fixation  Icon User is offline

  • D.I.C Head

Reputation: 41
  • View blog
  • Posts: 179
  • Joined: 01-November 11

Posted 25 January 2012 - 12:44 AM

Really good tutorial, thanks a lot, I'm just stepping into C# and that was informative and thorough. :)
Was This Post Helpful? 0
  • +
  • -

#4 h4nnib4l  Icon User is offline

  • The Noid
  • member icon

Reputation: 1175
  • View blog
  • Posts: 1,661
  • Joined: 24-August 11

Posted 21 January 2013 - 03:08 PM

Excellent tutorial, very informative!

NOTE: On line 19 of your final example (where you show the initial definitions of the FirstCaller, SecondCaller, and EndOfCallStack classes), in the comments you say that SecondCaller.Divide converts the numbers to doubles, but you're calling int.Parse, not double.Parse.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1