Aggregate exceptions / multiple exceptions from one method
Who says you cannot throw multiple exceptions in one method. If you are not used to playing around with AggregateExceptions you may be tempted to create your own data-structure to represent many things going wrong. There are of course were another data-structure that is not an exception would be more ideal such as the results of a validation. Even if you do play with AggregateExceptions you may be on the receiving side and always handling them not realizing they can be of use to you.
It is quite plausible to have a method execute and even though it will be a failure as a whole you will want to highlight multiple things that went wrong in the exceptions that are thrown. As an example this behavior can be seen with how Parallel methods work were a task broken into multiple threads and any number of them could throw exceptions and this needs to be reported. Here is a silly example of how you could benefit from this:
Basic Exception Handling
Note that handling all exceptions with the same code is often not the best approach.
This is commonly used when any inner exception handling routines fail, as a last resort.
Control flow with control statements
Control flow with exceptions
Keep track of ignored (absorbed) exception by logging
Repeat exception by using throw
Re-throw exception - throw new ArgumentNullException() or throw ex
Throw predefined system exceptions
Throw custom exceptions similar to predefined system exceptions
Throw custom/predefined exception if it is crucial to application logic
Throw custom/predefined exceptions to state a warning in flow
Catch exceptions that you want to handle
Catch every exception
DO NOT manage business logic with exceptions.
Flow control should NOT be done by exceptions. Use conditional statements instead. If a control can be done with if-else statement clearly, don't use exceptions because it reduces readability and performance.
Consider the following snippet by Mr. Bad Practices:
When execution reaches Console.WriteLine(myObject.ToString()); application will throw an NullReferenceException. Mr. Bad Practices realized that myObject is null and edited his snippet to catch & handle NullReferenceException:
Since previous snippet only covers logic of exception, what should I do if myObject is not null at this point? Where should I cover this part of logic? Right after Console.WriteLine(myObject.ToString());? How about after the try...catch block?
How about Mr. Best Practices? How would he handle this?
Mr. Best Practices achieved same logic with fewer code and a clear & understandable logic.
DO NOT re-throw Exceptions
Re-throwing exceptions is expensive. It negatively impact performance. For code that routinely fails, you can use design patterns to minimize performance issues. This topic describes two design patterns that are useful when exceptions might significantly impact performance.
DO NOT absorb exceptions with no logging
Never swallow exceptions. Ignoring exceptions will save that moment but will create a chaos for maintainability later. When logging exceptions, you should always log the exception instance so that the complete stack trace is logged and not the exception message only.
Do not catch exceptions that you cannot handle
Many resources, such as this one, strongly urge you to consider why you are catching an exception in the place that you are catching it. You should only catch an exception if you can handle it at that location. If you can do something there to help mitigate the problem, such as trying an alternative algorithm, connecting to a backup database, trying another filename, waiting 30 seconds and trying again, or notifying an administrator, you can catch the error and do that. If there is nothing that you can plausibly and reasonably do, just "let it go" and let the exception be handled at a higher level. If the exception is sufficiently catastrophic and there is no reasonable option other than for the entire program to crash because of the severity of the problem, then let it crash.
Creating Custom Exceptions
You are allowed to implement custom exceptions that can be thrown just like any other exception. This makes sense when you want to make your exceptions distinguishable from other errors during runtime.
In this example we will create a custom exception for clear handling of problems the application may have while parsing a complex input.
Creating Custom Exception Class
To create a custom exception create a sub-class of Exception:
Custom exception become very useful when you want to provide additional information to the catcher:
Now, when you catch(ParserException x) you will have additional semantics to fine-tune exception handling.
Custom classes can implement the following features to support additional scenarios.
During the parsing process, the original exception is still of interest. In this example it is a FormatException because the code attempts to parse a piece of string, which is expected to be a number. In this case the custom exception should support the inclusion of the 'InnerException':
In some cases your exceptions may have to cross AppDomain boundaries. This is the case if your parser is running in its own AppDomain to support hot reloading of new parser configurations. In Visual Studio, you can use Exception template to generate code like this.
Using the ParserException
You may also use custom exceptions for catching and wrapping exceptions. This way many different errors can be converted into a single error type that is more useful to the application:
When handling exceptions by raising your own custom exceptions, you should generally include a reference the original exception in the InnerException property, as shown above.
If exposing the reason for the exception might compromise security by allowing users to see the inner workings of your application it can be a bad idea to wrap the inner exception. This might apply if you are creating a class library that will be used by others.
Here is how you could raise a custom exception without wrapping the inner exception:
When raising a custom exception (either with wrapping or with an unwrapped new exception), you should raise an exception that is meaningful to the caller. For instance, a user of a class library may not know much about how that library does its internal work. The exceptions that are thrown by the dependencies of the class library are not meaningful. Rather, the user wants an exception that is relevant to how the class library is using those dependencies in an erroneous way.
One should always re-throw exception in the following way:
Re-throwing an exception like below will obfuscate the original exception and will lose the original stack trace. One should never do this! The stack trace prior to the catch and rethrow will be lost.
There are almost no (some say none!) reasons to catch the generic exception type in your code. You should catch only the exception types you expect to happen, because you hide bugs in your code otherwise.
If any other exception happens, we purposedly let the application crash, so it directly steps in the debugger and we can fix the problem. We mustn't ship a program where any other exceptions than these happen anyway, so it's not a problem to have a crash.
The following is a bad example, too, because it uses exceptions to work around a programming error. That's not what they're designed for.
The try / catch / finally block can be very handy when reading from files.
A try block must be followed by either a catch or a finally block. However, since there is no catch block, the execution will cause termination. Before termination, the statements inside the finally block will be executed.
In the file-reading we could have used a using block as FileStream (what OpenRead returns) implements IDisposable.
Even if there is a return statement in try block, the finally block will usually execute; there are a few cases where it will not:
The application process is killed, usually by an external source.
Handling specific exception types
Be careful that exceptions are evaluated in order and inheritance is applied. So you need to start with the most specific ones and end with their ancestor.
At any given point, only one catch block will get executed.
Implementing IErrorHandler for WCF Services
Implementing IErrorHandler for WCF services is a great way to centralize error handling and logging. The implementation shown here should catch any unhandled exception that is thrown as a result of a call to one of your WCF services. Also shown in this example is how to return a custom object, and how to return JSON rather than the default XML.
In this example we attach the handler to the service behavior. You could also attach this to IEndpointBehavior, IContractBehavior, or IOperationBehavior in a similar way.
Attach to Service Behaviors:
Configs in Web.config:
Here are a few links that may be helpful on this topic:
Your code can, and often should, throw an exception when something unusual has happened.
Unhandled and Thread Exception
This event provides notification of uncaught exceptions.It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application.If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery.Caution is advised, because program data can become corrupted when exceptions are not handled.
This event allows your Windows Forms application to handle otherwise unhandled exceptions that occur in Windows Forms threads. Attach your event handlers to the ThreadException event to deal with these exceptions, which will leave your application in an unknown state. Where possible, exceptions should be handled by a structured exception handling block.
And finally exception handling
Using the exception object
You are allowed to create and throw exceptions in your own code.
Instantiating an exception is done the same way that any other C# object.
You can then use the throw keyword to raise the exception:
Note: If you're throwing a new exception inside a catch block, ensure that the original exception is passed as "inner exception", e.g.
In this case it is assumed that the exception cannot be handled but some useful information is added to the message (and the original exception can still be accessed via ex.InnerException by an outer exception block).
It will show something like:
System.DivideByZeroException: Cannot divide by b because it is zero ---> System.DivideByZeroException: Attempted to divide by zero.
at UserQuery.g__DoSomething0_0() in C:[...]\LINQPadQuery.cs:line 36
--- End of inner exception stack trace ---
at UserQuery.g__DoSomething0_0() in C:[...]\LINQPadQuery.cs:line 42
at UserQuery.Main() in C:[...]\LINQPadQuery.cs:line 55
If you're trying this example in LinqPad, you'll notice that the line numbers aren't very meaningful (they don't always help you). But passing a helpful error text as suggested above oftentimes significantly reduces the time to track down the location of the error, which is in this example clearly the line