How to Catch Multiple Exceptions in C#

Here's a technique for catching more than one exception in a try / catch block.  Typically it's best to only catch the exceptions that your code can handle, so catching the general System.Exception class is discouraged.  But in this case, we're catching the general Exception class only to determine what type of exception it is.  For any exceptions that aren't handled in the if / else if blocks, we'll re-throw the exception for the calling method to handle.

catch (Exception exception)
{
	if (exception is FileNotFoundException)
	{
		Console.WriteLine("Error: File not found");
	}
	else if (exception is ArgumentException || exception is ArgumentNullException || exception is DirectoryNotFoundException)
	{
		Console.WriteLine("Error: Path is invalid or does not exist");
	}
	else
	{
		throw;
	}
}

The entire console application (Program.cs):

// Code from www.jaypm.com
// Feel free to use, but please give credit where it's due.

using System;
using System.IO;

namespace MultipleExceptionHandler
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (var fileReader = new StreamReader("file.txt"))
                {
                    while (fileReader.Peek() > 0)
                    {
                        Console.WriteLine(fileReader.ReadLine());
                    }
                }
            }
            catch (Exception exception)
            {
                // Check if it's one of three different exceptions:
                if (exception is ArgumentException || exception is ArgumentNullException || exception is DirectoryNotFoundException)
                {
                    Console.WriteLine("Error: Path is invalid or does not exist");
                }
                // Otherwise check if it's another exception:
                else if (exception is FileNotFoundException)
                {
                    // NOTE: This was only an example to demonstrate handling multiple exceptions.
                    //        It's more efficient to use File.Exists(fileName) rather than using an exception
                    //        to drive your logic.
                    Console.WriteLine("Error: File not found");
                }
                // Since we caught the generic System.Exception, this "else" case will
                // throw back up anything that wasn't explicitly caught:
                else
                {
                    throw;
                }
            }
            Console.ReadLine();
        }
    }
}

IDisposable Interface and Managed Resources

Very scarcely I'll see a developer disposing an object and I'll admit that I'm one of those developers who doesn't do this enough.  We're all aware of the garbage collector that runs at indeterminate times to clean up the mess we've left behind, so who cares whether we actually call an object's Dispose() method?  Why not just wait until the garbage collector does its thing?

Because the garbage collector won't free up unmanaged resources in your code.  These are files, handles, and streams.  These objects implement the IDisposable interface, which has only one method, Dispose().

In C#, there are two techniques for disposing of an object that implements the IDisposable interface:

  • In a try / finallyblock:
    var memoryStream = new MemoryStream();
    var bytes = new byte[128];
    try
    {
    	memoryStream.Read(bytes, 0, bytes.Length);
    }
    finally
    {
    	memoryStream.Dispose();
    } 
  • In a using statement:
    var memoryStream = new MemoryStream();
    var bytes = new byte[128];
    using (memoryStream)
    {
    	memoryStream.Read(bytes, 0, bytes.Length);
    } 

In the case of a using statement, the Dispose() method is implied at the end and is guaranteed to run even if an exception is hit; it's a fancy way of implementing the try / finally block.

In addition, if any of your classes use unmanaged resources, you'll want to implement IDisposable too.  Here's an example.  Please feel free to let me know if you see any issues with this implementation.

public class SpecializedMemoryStream : IDisposable
{
	private MemoryStream _memoryStream;
	private bool _isDisposed;

	/// <summary>
	/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
	/// </summary>
	public void Dispose()
	{
		Dispose(true);

		// Tell the garbage collector that the finalize destructor doesn't need to be called for this object
		GC.SuppressFinalize(this);
	}

	/// <summary>
	/// The finalize destructor
	/// </summary>
	~SpecializedMemoryStream()
	{
		Dispose(false);
	}

	protected virtual void Dispose(bool isDisposingManagedResources)
	{
		// Check if this method was previously called:
		if (_isDisposed)
		{
			return;
		}

		if (isDisposingManagedResources)
		{
			// Free up managed resource:
			if (_memoryStream != null)
			{
				_memoryStream.Dispose();
				_memoryStream = null;
			}
		}

		// Dispose any native resources here.

		_isDisposed = true;
	}
}

It's definitely good practice to be on the eye out for objects that implement the IDisposable interface; although it takes a bit more code to implement correctly, it frees up resources that otherwise wouldn't have been reclaimed until your application closes and might help to prevent memory leaks along the way.

References:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
http://msdn.microsoft.com/en-US/library/ms244737(v=VS.80).aspx