In this third installment of C# Basics, let's take a look at exception handling. It is one the easiest things to do poorly in an application. In C# you can capture an error and do something with it as easily as this:
try
{
//do something that may raise an exception
}
catch (Exception e)
{
//do something with e--log it, modify a return value, etc.
//if you want the caller of your code to have a crack at the same exception
throw; //raise the exception again with throw; (almost NEVER throw e;)
}
But do try your best to NEVER catch the base Exception class. Be more specific, especially where you have to do something specific with a particular type of exception and allows others to rise up the call stack. Here’s just one example of being a bit more specific:
try
{
//call a service that reads data from SQL Server
}
catch (SqlException se)
{
if (se.Message.Contains("Timeout"))
{
//send a timeout log message to the DBA service
}
throw; //raise it up the stack to be handled by the caller
}
Of course, you can and ought to handle different exceptions differently where required. Here’s a brief example:
try
{
//call a service that reads data from SQL Server
//call another service that writes to a file
}
catch (SqlException se)
{
if (se.Message.Contains("Timeout"))
{
//send a timeout log message to the DBA service
}
throw; //raise it up the stack to be handled by the caller
}
catch (IOException iox)
{
//special handling or logging of IO exceptions
Console.WriteLine(iox.Message);
}
catch (Exception e)
{
//log a general exception and rethrow
throw;
}
And don’t forget, you can create your own specialized exception classes. In fact, with Visual Studio you can use the code snippet for Exception. Just put your cursor in a C# file, outside of a class declaration, and start typing Exception and when you see the Intellisense prompt just hit TAB TAB. And you will have the following:
[Serializable]
public class MyException : Exception
{
public MyException() { }
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
protected MyException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
Flesh out your own custom exception and raise and catch it just like a pro.
public void ShowExample(int count)
{
if (count < 0) throw new MyException("Count cannot be less than zero.");
// . . .
}
public void CallExample()
{
try
{
ShowExample(-4);
}
catch (MyException me)
{
Console.WriteLine(me.Message);
}
}
Of course, in the above example, you would more likely want to just throw a new ArgumentException. There is a very long list of commonly used exception classes in the .NET base class libraries. Spend some time on MSDN and get familiar with them. Here’s a brief but incomplete list of common exception classes you may want to catch or throw and then catch.
- System.ArgumentException
- System.ArgumentNullException
- System.ArgumentOutOfRangeException
- System.ArithmeticException
- System.DivideByZeroException
- System.FormatException
- System.IndexOutOfRangeException
- System.InvalidOperationException
- System.IO.IOException
- System.IO.DirectoryNotFoundException
- System.IO.EndOfStreamException
- System.IO.FileLoadException
- System.IO.FileNotFoundException
- System.IO.PathTooLongException
- System.NotImplementedException
- System.NotSupportedException
- System.NullReferenceException
- System.OutOfMemoryException
- System.Security.SecurityException
- System.Security.VerificationException
- System.StackOverflowException
- System.Threading.SynchronizationLockException
- System.Threading.ThreadAbortException
- System.Threading.ThreadStateException
- System.TypeInitializationException
- System.UnauthorizedAccessException