Design Guidelines Update: Exception Throwing


Exception Throwing

Exception throwing guidelines described in this section require a good definition of the meaning of execution failure. Execution failure occurs whenever a member cannot do what it was designed to do (what the member name implies). For example, if OpenFile method cannot return an opened file handle to the caller, it would be considered an execution failure.

Most developers have become comfortable with using exceptions for hard error cases such as division by zero or null references. In the Framework, exceptions are used for both hard errors and logical errors. At first, it can be difficult to embrace exception handling as the means of reporting all functional failures. However, it is important to design all public methods of a framework to report method-failures by throwing an exception.

There are a variety of excuses for not using exceptions, but most boil down to the two perceptions that exception handling syntax is undesirable, so returning an error code is somehow preferable, or that a thrown exception does not perform as well as  returning an error code. The performance concerns are addressed in the performance section below. The concern over syntax is largely a matter of familiarity and should not be a consideration. As an API designer we should not make assumptions about the familiarity of the application developers consuming our code. 

ý     Do not return error codes. Exceptions are the primary means of reporting errors in frameworks.

þ     Do report execution failures by throwing exceptions. If a member cannot successfully do what is designed to do, it should be considered an execution failure and an exception should be thrown.

þ     Consider terminating the process by calling System.Environment.FailFast (.NET Framework 2.0 feature) instead of throwing an exception, if your code encounters a situation where it is unsafe for further execution.

ý     Do not use exceptions for normal flow of control. Except for system failures, there should generally be a way to write code that avoids exceptions being thrown. For example, you can provide a way to check preconditions before calling a member to allow users to write code that does not throw exceptions.

ICollection<int> collection = …

if(!collection.IsReadOnly){

    collection.Add(additionalNumber);

}

The member used to check preconditions of another member is often referred to as a tester and the member that actually does the work is called a doer. See performance section below for more information on the Tester-Doer Pattern.

There are cases when the Tester-Doer pattern may have an unacceptable performance overhead. In such cases the so called TryParse Pattern (see section below) should be used.

þ     Consider performance implications of throwing exceptions. See section below for details.

þ     Do document all exceptions thrown by publicly callable members because of a violation of the member contract (rather than a system failure) and treat them as part of your contract. Exceptions that are a part of the contract should not change from one version to the next.

ý     Do not have public members that can either throw or not based on some option.

Type GetType(string name, bool throwOnError)

ý     Do not have public members that return exceptions as the return value or an out parameter.

þ     Do set all the relevant properties of the exception you throw.

þ     Consider using exception builder methods. It is common to throw the same exception from different places. To avoid code bloat, use helper methods that create exceptions and initialize their properties. For example:

class File{

   string fileName;

 

   public byte[] Read(int bytes){

      if (!ReadFile(handle, bytes))

            throw NewFileIOException(…);

   }

 

   FileException NewFileException(…){

      string description = // build localized string

      return new FileException(description);

   }

}

ý     Do not throw exceptions from exception filter blocks. When an exception filter raises an exception, the exception is caught by the CLR, and the filter returns false. This behavior is indistinguishable from the filter executing and returning false explicitly and is therefore very difficult to debug.

ý     Avoid explicitly throwing exceptions from finally blocks. Implicitly thrown exceptions resulting from calling methods that throw are acceptable. 

1.1.1 Choosing the Right Type of Exception to Throw

þ     Consider throwing existing exceptions residing in the System namespaces instead of creating custom exception types.

þ     Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exception. Otherwise, throw one of the existing exceptions.

ý     Do not create and throw new exceptions just to have ‘your team’s’ exception.

þ     Do throw the most specific (the most derived) exception that makes sense. For example, throw ArgumentNullException and not its base type ArgumentException if a null argument is passed.

1.2 Exceptions and Performance

One common concern related to exceptions is that if exceptions are used for code that routinely fails, the performance of the implementation will be unacceptable. This is a very valid concern. When a member throws an exception, its performance can be orders of magnitude slower. However, it is possible to achieve good performance while strictly adhering to the exception guidelines that disallow using error codes. Two patterns described in this section suggest ways to do this. 

ý     Do not use error codes because of concerns that exceptions might affect performance negatively.

Tester-Doer Pattern

Sometimes performance of an exception throwing member can be improved by breaking the member into two. Let’s look at the indexed property of the Dictionary class.

Dictionary<string,int> table = new Dictionary<string,int>();

int value = table[“key”];

The indexer throws if the key does not exist in the Dictionary. This can be a performance problem in scenarios where the lookup is expected to fail often. One of the ways to mitigate the problem is to test whether the key is in the dictionary before accessing the value.

Dictionary<string,int> table = new Dictionary<string,int>();

if(table.Contains(“key”)){

    int value = table[“key”];

}

The member used to test a condition, in our example the method Contains, is referred to as the ‘tester’. The member used to perform a potentially throwing operation, in our example the indexer, is referred to as the ‘Doer’. 

þ     Consider the Tester-Doer pattern for members which may throw exceptions in common scenarios to avoid performance problems related to exceptions.

TryParse Pattern

For extremely performance demanding APIs, an even faster pattern than the Tester-Doer described in the previous section should be used. The pattern is to adjust the member name to make a well-defined test case a part of the member semantics. For example, DateTime defines a Parse method that throws if parsing of a string fails. It also defines a corresponding TryParse method which attempts to parse, but returns false if parsing is unsuccessful and returns the result of a successful parsing using an out parameter.

public struct DateTime {

    public static DateTime Parse(string dateTime){

       

    }

    public static bool TryParse(string dateTime, out DateTime result){

       

    }

}

When using this pattern, it is important to define the ‘try’ functionality in strict terms. If the member fails for any reason other than the well defined try, then the member must still throw.

þ     Consider the TryParse pattern for members which may throw exceptions in common scenarios to avoid performance problems related to exceptions.

þ     Do provide an exception-throwing member for each member using the TryParse pattern.

Comments (54)

  1. Rolando says:

    &quot;Do not create and throw new exceptions just to have ‘your team’s’ exception.&quot;
    <br>
    <br>I was planning to do exactly that so we can identify exceptions thrown by our own code.
    <br>
    <br>Could you explain why this is a bad idea ?
    <br>
    <br>thanks.

  2. Python uses what is called the "samurai principle" for determining when to throw exceptions:

    Return a meaningfull and useable result or else throw an exception.

    I find that the standard prescription "exceptions are for exceptional circumstances" doesnt give much guidance, and welcome these new guidelines.

  3. "Do not return error codes. Exceptions are the primary means of reporting errors in frameworks."

    Blech. One more reason for me to stay away from .net.

  4. So what do you make of Thread.Abort() that (on Whidbey, if the thread is suspended) throws an exception *and* schedules an abort?

  5. mihailik says:

    Question on AgumentNullException.
    <br>
    <br>What exception to throw if my method does not allow &quot;&quot; (empty string) and such argument was passed in?
    <br>
    <br>In some place of CLR I have seen ArgumentNullException, but String.Empty is definitely not null. What is the guideline here?
    <br>
    <br>Please claim this option to official document, that all developers have to deal same way.

  6. Rolando says:

    &quot;Do not create and throw new exceptions just to have ‘your team’s’ exception.&quot;
    <br>
    <br>Could you explain why ?
    <br>
    <br>We were planning to do this so we can identify the exceptions thrown by our code.
    <br>

  7. mihailik says:

    Jacques Troux: it is phylosophical discussion. Miguel de Icaza — leader of Mono, a.k.a. .NET for Linux — Miguel votes for error codes in some of his old messages. And you can find the interview with Anders Heilsberg — author of C# — that expressively votes for exceptions.
    <br>
    <br>All .NET ideology built with exceptions, and it is extrmely important for security and stability.

  8. Joe Duffy says:

    Jeroen, you’re correct about the behavior.
    <br>
    <br>I wouldn’t recommend following the pattern that Thread.Abort() uses. (Note: I wouldn’t recommend suspending and asynchronously aborting threads either, but that’s a wildly separate topic. :))
    <br>
    <br>The behavior is strange. It succeeds at provoking an abort, but does throw an exception.
    <br>
    <br>I wish we could change it, but it’s been that way since 1.0.

  9. What does FailFast do? I can’t find any documentation on it.

  10. Jeffrey Sax says:

    This guideline is mostly excellent, but confusing in one respect.

    This performance rule:

    "Do not use error codes because of concerns that exceptions might affect performance negatively."

    is violated by the TryParse pattern. The TryParse pattern is worded nicely, but still clearly uses an error code to indicate success or failure.

    This contradiction, and the confusion that comes with it, disappear if you qualify the first rule with "except in extremely performance demanding APIs," and then suggest to "Do use" the TryParse pattern for these situations.

  11. System.Environment.FailFast offers the user a chance to send an error report, then terminates the process. (It’s the nicer managed equivalent to calling ExitProcess when you decide you really can’t go on.) If you’re writing a class library you probably don’t want to use FailFast–at least not if you like having customers :-D. If you’re writing an application, though, it often makes sense if you really want the process to die. Exceptions can be caught; FailFast just kills the process right away.

  12. Jonathan Keljo [MS] says:

    Here’s how I think about the performance rule and Parse vs. TryParse:
    <br>
    <br>Parse says it’s going to parse something. “Failure” means it couldn’t parse it. So exceptions from Parse could include exceptions because what you passed to it wasn’t parseable. The return value is the result of the operation—the parsed value.
    <br>
    <br>TryParse says it’s going to try to parse something. “Failure” means that it wasn’t even able to _try_ to parse the thing. Thus the only kinds of exceptions you’re going to get out of TryParse are things like OutOfMemory from JITting or allocating buffers before it even gets a chance to look at the string to be parsed. (You wouldn’t expect to get an exception because the value wasn’t parseable…the point is the method said it was going to try, and it did try. It did what it said it would, so no exception needed.) TryParse really has two results—was the thing parseable, and if so the parsed value.
    <br>

  13. Vincent says:

    Hello,

    FYI: your blog renders completely wrong in Firefox.

  14. "FYI: your blog renders completely wrong in Firefox."

    Um… In IE, too!?!? (IE6 on Wn2003)

    OTOH, like the contents and the reasoning.

  15. dan says:

    It isn’t clear whether you prohibit exceptions from /containing/ error codes (as a property). This ought to be allowed, because in some circumstances your only other options are (a) having a huge set of different exception types or (b) parsing the exception message to figure out what exactly happened.
    <br>An example of this problem is XmlException, which can be thrown for 1000 different reasons and needs an error code property to distinguish it.

  16. Recently somebody asked me to clarify one of the exception guidelines. They were asking whether it’s…

  17. Jeff Stong says:

    In a recent post I mentioned the .NET framework design guidelines and that reminded me of a post by Krzyztof…

  18. My last post about the ApplicationException resulted in some questions along the lines of “so, if not…

  19. JP says:

    The use of the word Throw has mulitple meanings in .net.  As a result the article is somewhat ambiguous.  In object oriented design, the standard of an object is that it is responsible for it’s own function.  Therefore, it is my understanding that objects and or methods within, should not Throw anything.  Instead they should handle the exception and move on.  Does your term throw mean "Handle the exception and inform the user?"  

  20. I agree that the term “throwing” is a bit ambiguous. It means either executing the throw statement or allowing an exception propagate out of a publicly callable API.

    I am not sure why you interpret throwing as handling exceptions and showing them to users. Could you point me to any particular statements that might imply so?

    As to objects handling exceptions and moving on, I think it’s only true for some kinds of exceptions. There are others that simply cannot be handled because the object does not have enough context to know how to fix the state of the system in the exception handler so it could continue safely. Those can sometimes be handled higher up on the stack, but in some cases they cannot be handled at all, and the best approach is to record as much information as possible and shut down the process/app domain.

    JP, please feel free to email me directly (kcwalina_at_microsoft.dot_com) if you’d like to talk about this more.

  21. AlSki says:

    I came across this article on Exception Throwing by Krysztof Cwalina, and I didn’t think its all very good advice… (See http://www.alski.net/software/Throwing+Exceptions.aspx)

  22. AlSki, I posted a reply comment on your blog. I hope it clarifies some things. Please don’t hesitate to email me at kcwalina_at_microsoft.com. I would be happy to discuss more detail.

  23. Chris says:

    Can you provide some guidance for how to structure a hierarchy of exception classes?  I cannot find any information addressing this design issue.  Should exceptions be grouped by the type of data that the error is associated with, or by the type of error.  I think they should be organized by the type of error, but it is very difficult to group errors this way.  Thank you for any input you may have.

  24. NigelAston says:

    How would you recommend handling multiple ‘error’ types that are passed back from hardware devices? For example we are a driving a motor to cause movement, and the command ‘move()’ can fail for many reasons such as ‘HitEndStop’, "Stall", "PowerLoss". Currently we would do something like:

    CError MoveTheDevice()

    {

       CError error = Move();

       if (error.IsOk)

       {

       //… continue processing

       }

       return error;   // to pass status higher up

    }

    Should we create lots of exception types and map the device errors to exception types?

    or

    should we throw an exception, having recorded the ‘error’ code somewhere – maybe as a ‘parameter’  within the exception.

  25. Sloan says:

    Krzysztof ,

    Thank you for the great article.  Your ideas are clear and well laid out, and have helped tremendously.

    NigelAston,

    One way I deal with this scenario is using a "base" exception.

    public abstract class HardwareFailureException : System.ApplicationException

    public class HitEndStopException : HardwareFileException

    public class PowerLossException : HardwareFileException

    Then I believe you can just catch the HardwareFileException exception in your code.

    Give it a try!

  26. CVC says:

    Performance is a criteria to take into consideration, but one criteria that is not included in this article is code flow, throwing exceptions sometimes makes you code flow nicer than trying to exit your method earlier and trying to clean up, when you finally statement could handle that, returning error codes from your method when it happens, etc…. I assume that this guidelines apply to exceptions that could occur in .net system classes, but what about classes that I create? If have not seen any issues with performance in throwing exceptions in my production application…It has made the flow of my program much cleaner and easier to understand.

  27. Buff… cuanto tiempo desde mi último post, entre estudiar y la medio-gripe que arrastro desde hace unas

  28. vtortola says:

    Buff… cuanto tiempo desde mi último post, entre estudiar y la medio-gripe que arrastro desde hace unas

  29. Ivara blogs says:

    &#352;odien &#160; Vakar Andrejs jau aizskāra tēmu, par kuru es jau pasen gribu uzrakstīt, bet kaut kā

  30. rakhs says:

    Gud one.

    how we can throw exceptions from Appdomain "A" to appDomain "B".

    Scenario:

    In AppDomain "B" create a thread and from worker thread call a method in AppDomain "A" , which throws an exception. How we can catch this exception in AppDomain "B"

  31. Janko's Blog says:

    Exception handling plays an important part of application management and user experience. If implemented

  32. Licantrop0 says:

    Hi Krzysztof, Iv’e bought your book and is one of my favourites.

    I wanna ask if you can spend some word about the bad design to rise normal events (named "whateverError" or "whateverException") instead of throwing exceptions.

    thanks.

  33. In rare cases it’s better to communicate errors through events. This is true mainly for asynchronous APIs where the original caller thread is long doing some other things and we can not throw to that thread anymore.

  34. Licantrop0 says:

    Thanks for your reply.

    So except for multithreading environment, throwing exception is always the best way. I have many colleagues that sadly mix up event and exception so "you can manage what you prefer!" … 😐

    Could you please write a little explanation about this in your new book?, so if "the .net guidelines bible said so", they can’t complain… 🙂

    regards!

  35. I will try to clarify that in the book (2nd edition), but it already says that exceptions should be the default and other means of communicating errors should be very rare.

  36. GrabBag says:

    This post was originally published here . I recently posted on the out and ref keywords in C#, and mentioned

  37. Andrei Rinea says:

    A person asked above what should do in case the method called gets an empty string (String.Empty) and such a value is not acceptable?

    Throwing an ArgumentNullException is not the best idea and ArgumentException might be a little too ambigous.

    I always thought of ArgumentEmptyException as an exception class derived from ArgumentException.

    What can you tell us about this issue?

  38. VS says:

    mihailik:

    AFAIK, there is no built in Exception class to check for empty arguments. What I can suggest is this:

    In your method, do this:

    if String.IsNullOrEmpty(param)

    {

      throw new ArgumentException("The param cannot be null or an empty string.");

    }

    Can somebody comment?

  39. Ivan Belov says:

    "TryDo" sounds like more appropriate name for what you call "TryParse" pattern. Or am I wrong?

  40. Ivan, it's possibly a better name, but TryParse just stuck for historical reasons.