#899 – Exception Type Variable in a catch Block Is Optional

In a catch block that specifies a particular exception type to catch, you’ll typically include a named variable representing the exception object that is caught.  Using this variable, code within your handler can access information about the exception that was caught.

            try
            {
                Dog d = new Dog("Kirby", 15);
                d.Bark(BarkSound.Woof, 99);
            }
            catch (DogBarkException dbe)
            {
                Console.WriteLine("Kirby didn't bark properly");
                Console.WriteLine(string.Format("Can't bark {0} times", dbe.NumTimes));
            }

If you don’t need to access data within the exception object, but you still want to catch exceptions of a specific type, you can omit the variable.  This will allow you to catch exceptions of a particular type, but not give you any access of data within the exception object.

            try
            {
                Dog d = new Dog("Kirby", 15);
                d.Bark(BarkSound.Woof, 99);
            }
            catch (DogBarkException)
            {
                Console.WriteLine("Kirby didn't bark properly");
            }

#898 – Using Code Snippets to Implement a Custom Exception Type

Visual Studio includes a code snippet that makes it easier to implement a custom exception type.

To add a custom exception type using a code snippet, start by adding a new class file to your project and naming it to match your exception type.

898-001

898-002

 

In the new class, delete the class definition, so that all that remains in the file is a namespace definition.

898-003

 

Create a new blank line within the namespace definition.  Begin typing the word “exception” and look for the icon in the Intellisense dropdown that indicates a code snippet.

898-004

 

Press the TAB key twice so that the code snippet is inserted.  The definition of a new class that derives from Exception will be inserted.

898-005

 

While the name of the new class is highlighted, type the name of your new exception type and press TAB.  The new exception type name will be inserted where appropriate.

898-006

 

#897 – Rules for Creating a Custom Exception Type

The basic guidelines for defining your own custom exception types are as follows:

  • Derive from one of the following:
  • End the name of your type with “Exception”  (e.g. InvalidDogBarkException)
  • Mark your exception type as Serializable
  • Define the following constructors:
    • public MyException()
    • public MyException(string message) : base(message)
    • public MyException(string message, Exception inner) : base(message, inner)
    • public MyException(SerializationInfo info, StreamingContext context) : base(info, context)
  • Consider adding custom data:
    • Add one or more custom properties
    • Add one or more constructor that accept values for the custom properties

Click here for a full example.

 

 

#896 – Custom Exceptions Should Be Marked as Serializable

Whenever you create a custom exception type, your exception type should always support serialization.  You do this using the Serializable attribute.  Exceptions should be serializable so that they can automatically be marshalled across application domains or threads.

At a minimum, you should mark your custom exception as serializable and implement the four basic constructors shown below.  (This example shows a custom exception type that has no custom data).

    [Serializable]
    public class DogBarkException : Exception
    {
        public DogBarkException()
        {
        }

        public DogBarkException(string message)
            : base(message)
        {
        }

        public DogBarkException(string message, Exception innerException)
            : base(message, innerException)
        {
        }

        protected DogBarkException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
    }

Note: For access to the SerializationInfo and StreamingContext types, you’ll need the following using statement:

using System.Runtime.Serialization;

#895 – Catching a Custom Exception Type

You might define a custom exception if you want to add custom data to an exception that you throw or if you just want calling code to be able to check for your specific exception.

In the example below, we’ve created a custom exception type, DogBarkException, that we throw when we have a problem in the Dog.Bark method.  The exception contains all of the normal data found in an instance of Exception, as well as additional information about the dog and the attempted bark.

            try
            {
                Dog d = new Dog("Buster", 5);
                d.Bark(BarkSound.Woof, 12);
            }
            catch (DogBarkException xx)
            {
                Console.WriteLine(xx.ToString());
                Console.WriteLine("Dog {0}, aged {1}, couldn't bark",
                    xx.DogName, xx.DogAge);
                Console.WriteLine("  Attempted {0} bark, {1} times",
                    xx.BarkSound, xx.BarkNumTimes);
            }

If we set a breakpoint within the catch block, we can examine the various properties of the DogBarkException object.

895-001

#894 – Creating a Custom Exception Type with Custom Data

You might create a custom exception type that doesn’t extend the base Exception type.  But quite often it’s useful to add some additional data that is specific to your exception type.

In the example below, we create a new exception type that stores two additional fields related to the Dog.Bark operation that failed.

    public enum BarkSound { Yip, Arf, Woof };

    public class DogBarkException : Exception
    {
        public DogBarkException()
        {
        }

        public DogBarkException(string message)
            : base(message)
        {
        }

        public DogBarkException(string message, Exception innerException)
            : base(message, innerException)
        {
        }

        public BarkSound Sound { get; set; }
        public int NumTimes { get; set; }

        public DogBarkException(string message, BarkSound sound, int numTimes)
            : base(message)
        {
            Sound = sound;
            NumTimes = numTimes;
        }
    }

We can now throw a new instance of this exception type as follows:

            if ((barkSound == BarkSound.Woof) && (numTimes > 5))
                throw new DogBarkException("Dogs can't woof more than 3 times in a row", barkSound, numTimes);

#893 – A Custom Exception Type Doesn’t Need to Add Custom Data

You may sometimes define a custom exception type without adding any additional data to the base Exception type.  This can still add value, because calling code can now explicitly check for your new exception type.  In this way, you’re not adding custom data to the exception that you throw, but you’re adding information by indicating the specific type of exception that occurred.

Assume that we’ve defined a DogBarkException type, which can be thrown by the Dog.Bark method.  We can then check for this exception when calling Dog.Bark.

            try
            {
                Dog d = new Dog("Buster", 5);
                d.Bark(Dog.BarkSound.Woof, 6);
            }
            catch (DogBarkException xx)
            {
                Console.WriteLine("Problem with barking!");
                Console.WriteLine(xx.Message);
            }
            catch (Exception xx)
            {
                Console.WriteLine("Something went wrong:");
                Console.WriteLine(xx);
            }

893-001