What are some best practices for creating my own custom exception?
Asked Answered
T

5

24

In a follow-up to a previous question regarding exceptions, what are best practices for creating a custom exception in .NET?

More specifically should you inherit from System.Exception, System.ApplicationException or some other base exception?

Theosophy answered 10/9, 2008 at 17:55 Comment(1)
See this question: <#53253>Chesney
B
16

Inherit from System.Exception. System.ApplicationException is useless and the design guidelines say "Do not throw or derive from System.ApplicationException."

See http://blogs.msdn.com/kcwalina/archive/2006/06/23/644822.aspx

Batiste answered 10/9, 2008 at 17:57 Comment(6)
According to Jeffrey Richter, the original idea was that classes derived from SystemException would indicate exceptions thrown from the CLR (or system) itself, whereas non-CLR exceptions would be derived from ApplicationException. But since a lot of of exception classes thrown by the CLR didn’t follow this pattern, the ApplicationException class lost all meaning. The reason to derive from this base class is to allow some code higher up the call stack to catch the base class but it's impossible to catch all application exceptions since some CLR exceptions inherit from ApplicationException.Batiste
@MarkCidade: The fact that some CLR exceptions inherit from ApplicationException might actually be a good thing if there were a consistent distinction in the hierarchy between exceptions which mean "The operation couldn't succeed, but the attempt didn't do anything; if you're prepared for that, great", versus "Something has gone so horribly wrong that almost everything should be presumed corrupt; the only reasons not to shut things down instantly would be if one wants to capture diagnostic information or trigger an automatic relaunch, first." Too bad there's no such distinction.Disappearance
@Disappearance It might be the case that the context of the application determines whether doing nothing is recoverable or is a reason to fail fast (e.g., almost-real-time systems where something HAS to be successfully attempted all the time).Batiste
@MarkCidade: In some situations, such as when deserializing an object, explicitly accounting for all the things that might go wrong would greatly complicate code. In many cases, if a data stream cannot be deserialized to yield a valid object, one really doesn't care why. What one does care about is whether the attempt to load the datastream causes or indicates any problem beyond "document could not be opened". If 99% of the exceptions which could occur while deserializing a document should have those same semantics, it would be nice to be able to...Disappearance
@MarkCidade: ...catch those 99% of exceptions without having to identify them all, and yet still not catch and swallow the 1% which indicate deeper problems. It's too bad neither vb.net nor C# offers fault blocks, since the proper behavior if an unexpected exception might leave an object in an invalid state would be to invalidate the object so most future actions will throw immediate exceptions. If the object is abandoned, its corruption will be a non-issue. If it's critical to operation, its invalidation will force a shutdown.Disappearance
A well-designed library can use a single base exception for "document could not be opened", similar to ArgumentException vs. ArgumentNullException,ArgumentOutOfRangeException, etc., but whether that's a critical thing or can be re-tried, or ignored, is still completely up to the application that uses that library.Batiste
S
26

In the C# IDE, type 'exception' and hit TAB. This will expand to get you started in writing a new exception type. There are comments withs links to some discussion of exception practices.

Personally, I'm a big fan of creating lots of small classes, at that extends to exception types. For example, in writing the Foo class, I can choose between:

  1. throw new Exception("Bar happened in Foo");
  2. throw new FooException("Bar happened");
  3. throw new FooBarException();

where

class FooException : Exception 
{
    public FooException(string message) ... 
}

and

class FooBarException : FooException 
{
    public FooBarException() 
        : base ("Bar happened") 
    {
    }
}

I prefer the 3rd option, because I see it as being an OO solution.

Stellite answered 10/9, 2008 at 18:27 Comment(0)
B
16

Inherit from System.Exception. System.ApplicationException is useless and the design guidelines say "Do not throw or derive from System.ApplicationException."

See http://blogs.msdn.com/kcwalina/archive/2006/06/23/644822.aspx

Batiste answered 10/9, 2008 at 17:57 Comment(6)
According to Jeffrey Richter, the original idea was that classes derived from SystemException would indicate exceptions thrown from the CLR (or system) itself, whereas non-CLR exceptions would be derived from ApplicationException. But since a lot of of exception classes thrown by the CLR didn’t follow this pattern, the ApplicationException class lost all meaning. The reason to derive from this base class is to allow some code higher up the call stack to catch the base class but it's impossible to catch all application exceptions since some CLR exceptions inherit from ApplicationException.Batiste
@MarkCidade: The fact that some CLR exceptions inherit from ApplicationException might actually be a good thing if there were a consistent distinction in the hierarchy between exceptions which mean "The operation couldn't succeed, but the attempt didn't do anything; if you're prepared for that, great", versus "Something has gone so horribly wrong that almost everything should be presumed corrupt; the only reasons not to shut things down instantly would be if one wants to capture diagnostic information or trigger an automatic relaunch, first." Too bad there's no such distinction.Disappearance
@Disappearance It might be the case that the context of the application determines whether doing nothing is recoverable or is a reason to fail fast (e.g., almost-real-time systems where something HAS to be successfully attempted all the time).Batiste
@MarkCidade: In some situations, such as when deserializing an object, explicitly accounting for all the things that might go wrong would greatly complicate code. In many cases, if a data stream cannot be deserialized to yield a valid object, one really doesn't care why. What one does care about is whether the attempt to load the datastream causes or indicates any problem beyond "document could not be opened". If 99% of the exceptions which could occur while deserializing a document should have those same semantics, it would be nice to be able to...Disappearance
@MarkCidade: ...catch those 99% of exceptions without having to identify them all, and yet still not catch and swallow the 1% which indicate deeper problems. It's too bad neither vb.net nor C# offers fault blocks, since the proper behavior if an unexpected exception might leave an object in an invalid state would be to invalidate the object so most future actions will throw immediate exceptions. If the object is abandoned, its corruption will be a non-issue. If it's critical to operation, its invalidation will force a shutdown.Disappearance
A well-designed library can use a single base exception for "document could not be opened", similar to ArgumentException vs. ArgumentNullException,ArgumentOutOfRangeException, etc., but whether that's a critical thing or can be re-tried, or ignored, is still completely up to the application that uses that library.Batiste
F
5

There is a code snippet for it. Use that. Plus, check your code analysis afterwards; the snippet leaves out one of the constructors you should implement.

Frustule answered 10/9, 2008 at 17:58 Comment(0)
L
1

I think the single most important thing to remember when dealing with exceptions at any level (making custom, throwing, catching) is that exceptions are only for exceptional conditions.

Luisaluise answered 10/9, 2008 at 17:56 Comment(0)
N
1

The base exception from where all other exceptions inherit from is System.Exception, and that is what you should inherit, unless of course you have a use for things like, say, default messages of a more specific exception.

Nucleolated answered 10/9, 2008 at 17:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.