An exception reports an error and transfers control to a handler (C# specification
clause 22). All exceptions derive from System.Exception. C# has no checked
exceptions: a method does not declare what it may throw, and nothing requires a caller to
handle one.
throw
throw new ArgumentNullException(nameof(name));
try { Save(); }
catch (IOException)
{
Log();
throw; // rethrows, keeping the original stack trace
}
string s = name ?? throw new ArgumentNullException(nameof(name)); // throw expression, C# 7.0
- The operand must be of type
System.Exception, a class derived from it, or a type parameter constrained to it (clause 13.10.6). If it evaluates to null, aNullReferenceExceptionis thrown instead. - A plain
throw;is allowed only in acatchblock. It rethrows the current exception and preserves its stack trace.throw ex;resets the stack trace to this point. System.Runtime.ExceptionServices.ExceptionDispatchInforethrows an exception later and keeps its original trace.
try, catch and finally
try_statement:
try block catch_clauses
try block [catch_clauses] finally block
specific_catch_clause:
catch ( type [identifier] ) [exception_filter] block
general_catch_clause:
catch [exception_filter] block
exception_filter:
when ( boolean_expression )
try
{
Process(path);
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.FileName);
}
catch (IOException e) when (e.HResult == 32)
{
Retry();
}
catch (Exception)
{
throw;
}
finally
{
Cleanup();
}
- A
tryneeds at least onecatchor afinally. - Catch clauses are tried in order (clause 13.11). A clause for a base type before one for a derived type is a compile-time error, because the later clause could never run.
- A
catchwithout a type catches everything, and can appear once, last. - A
finallyblock runs when thetrystatement is left in any way: normally, by a jump, or by an exception. Control cannot jump out of it withreturnorgoto. An exception thrown inside replaces the one in flight. awaitis allowed incatchandfinallysince C# 6.
Exception filters
A when clause (C# 6) runs a condition after the type matches. If it is
false, the search continues with the next clause. A filter runs before the stack
unwinds, so it can log an exception without disturbing it.
How an exception is handled
When an exception is thrown, the runtime searches the enclosing try
blocks in the current function, then in each caller, for a matching catch
(clause 22.4). When it finds one, it runs the finally blocks of the
abandoned frames and then that clause. If none matches, the program terminates; whether
the finally blocks run in that case depends on the implementation.
The Exception class
| Member | Meaning |
|---|---|
Message | Text describing the error |
InnerException | The exception that caused this one, if any |
StackTrace | The call stack at the throw |
Source, TargetSite | The application and method involved |
Data | Extra key and value pairs |
HResult | A numeric error code |
public class ParseException : Exception
{
public ParseException(string message, Exception? inner = null) : base(message, inner) { }
public int Line { get; init; }
}
Common exception classes
The runtime throws these for failures of basic operations (clause 22.5):
| Exception | Thrown when |
|---|---|
ArithmeticException | Base class for arithmetic errors, such as the two below |
DivideByZeroException | An integer or decimal is divided by zero |
OverflowException | An operation overflows in a checked context |
IndexOutOfRangeException | An array index is out of range |
ArrayTypeMismatchException | An element of the wrong type is stored in an array |
InvalidCastException | A cast or unboxing fails at run time |
NullReferenceException | A null reference is used |
OutOfMemoryException | Memory cannot be allocated |
StackOverflowException | The stack is exhausted |
TypeInitializationException | A static constructor throws |
Libraries often throw ArgumentException and its subclasses
ArgumentNullException and ArgumentOutOfRangeException,
and InvalidOperationException and NotSupportedException.
See also exceptions
in async methods.