To create a custom exception, create a subclass of the Exception class, like this:
public class SimpleCustomException : Exception
{
public SimpleCustomException(string message) : base(message) { }
public SimpleCustomException() { }
}
Code language: C# (cs)
Then throw it just like you would any other exception, like this:
throw new SimpleCustomException("Cannot call this method on days that end with 'y'")
Code language: C# (cs)
It’s a good idea to call the base constructor from your constructor and pass in your custom error message. If this exception is unhandled, or if you are logging the exception, then it’ll show the exception name and message, like this:
SimpleCustomException: Cannot call this method on days that end with 'y'
Code language: plaintext (plaintext)
Example – Throwing a custom exception when invalid data is passed in
Creating your own custom exceptions allows you to create very specific exceptions. Throwing and catching very specific exceptions is part of clean error handling.
The following example shows a binary string parser class that throws a custom exception when invalid data is passed in. It throws a very specific exception explaining exactly what the problem is and what data is expected.
1 – Add a custom exception class
This custom exception is taking the invalid binaryString and putting it into an error message that explains what the expected format is, and includes an example of valid input.
public class InvalidBinaryStringException : Exception
{
public InvalidBinaryStringException(string binaryString)
: base($"Bad binary string: {binaryString}. Binary string must be 0's and 1's and the length must be a multiple of 8. Example: 00000001.")
{
}
}
Code language: C# (cs)
2 – Throw the exception when error conditions are detected
Before trying to parse the binary string, the BinaryStringUtil class checks the passed in binaryString, and throws the custom InvalidBinaryStringException if the input is invalid.
public class BinaryStringUtil
{
public static byte[] Parse(string binaryString)
{
if (binaryString.Length % 8 != 0 || Regex.IsMatch(binaryString, "[^01]"))
{
throw new InvalidBinaryStringException(binaryString);
}
//Parse binaryString into byte[]
return new byte[] { };
}
}
Code language: C# (cs)
You may be wondering, why not throw ArgumentException or FormatException instead? True, you could throw these exceptions and pass in the same error message. However, consider the following reasons for using custom exceptions:
- You encapsulate error messages. Notice how the code above is simply passing in the binaryString to the exception?
- Let’s say you’re using a log monitoring tool (like Splunk) and want to send alert emails when this specific error happens. You can simply look for “InvalidBinaryStringException” in the log. If you were using ArgumentException, you’d have to look for the error message instead (“Bad binary string…”).
- The client code can catch InvalidBinaryStringException and handle it properly. Let’s say your parsing code has a bug and some method you’re calling is throwing ArgumentException. If the client were catching this non-specific exception, the client code would have the wrong error handling behavior, and your bug would be hidden.
3 – Add unit tests to prove the code throws exceptions
The following parameterized unit tests tests the two error conditions: when the binary string isn’t a valid length and when it has invalid characters.
[DataRow("01")]
[DataRow("0100000a")]
[TestMethod()]
public void ParseTest_WhenBadBinaryString_ThrowsException(string binaryString)
{
Assert.ThrowsException<InvalidBinaryStringException>(() => BinaryStringUtil.Parse(binaryString));
}
Code language: C# (cs)
Notice that it’s using Assert.ThrowsException instead of the ExpectedException attribute.
Nice article!
In certain situacions, you have a class and you want to create specific exceptions for that class. However, custom exceptions are created as new classes. I would find it more clear if custom exceptions could be part of the class itself, like a field or method or subclass. Maybe subclass is the way. It is actually possible using a public subclass. What do you think?
I think what you’re looking for is a nested class. You can make the custom exception class a nested class, like this:
public class BinaryStringUtil
{
public class CustomException : Exception
{
}
public static void ThrowEx()
{
throw new CustomException();
}
…
Then all other code has to refer to the custom exception class by using the parent class’s name, like this:
catch(BinaryStringUtil.CustomException)
NOTE: If the nested class is public, then any other code could throw that exception, but they would always have to use the parent class’s name. If you make it private, then other code can’t throw or refer to this class. If you need other code to refer to it, and have it be private, then you can add an interface. It really depends on scenario and how much you want to restrict other code from using that exception. In my opinion, I would keep it simple and just keep the nested custom exception as public.