Exceptions: The try...with Expression
This topic describes the try...with
expression, the expression that is used for exception handling in F#.
Syntax
try
expression1
with
| pattern1 -> expression2
| pattern2 -> expression3
...
Remarks
The try...with
expression is used to handle exceptions in F#. It is similar to the try...catch
statement in C#. In the preceding syntax, the code in expression1 might generate an exception. The try...with
expression returns a value. If no exception is thrown, the whole expression returns the value of expression1. If an exception is thrown, each pattern is compared in turn with the exception, and for the first matching pattern, the corresponding expression, known as the exception handler, for that branch is executed, and the overall expression returns the value of the expression in that exception handler. If no pattern matches, the exception propagates up the call stack until a matching handler is found. The types of the values returned from each expression in the exception handlers must match the type returned from the expression in the try
block.
Frequently, the fact that an error occurred also means that there is no valid value that can be returned from the expressions in each exception handler. A frequent pattern is to have the type of the expression be an option type. The following code example illustrates this pattern.
let divide1 x y =
try
Some (x / y)
with
| :? System.DivideByZeroException -> printfn "Division by zero!"; None
let result1 = divide1 100 0
Exceptions can be .NET exceptions, or they can be F# exceptions. You can define F# exceptions by using the exception
keyword.
You can use a variety of patterns to filter on the exception type and other conditions; the options are summarized in the following table.
Pattern | Description |
---|---|
:? exception-type | Matches the specified .NET exception type. |
:? exception-type as identifier | Matches the specified .NET exception type, but gives the exception a named value. |
exception-name(arguments) | Matches an F# exception type and binds the arguments. |
identifier | Matches any exception and binds the name to the exception object. Equivalent to :? System.Exception asidentifier |
identifier when condition | Matches any exception if the condition is true. |
Examples
The following code examples illustrate the use of the various exception handler patterns.
// This example shows the use of the as keyword to assign a name to a
// .NET exception.
let divide2 x y =
try
Some( x / y )
with
| :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None
// This version shows the use of a condition to branch to multiple paths
// with the same exception.
let divide3 x y flag =
try
x / y
with
| ex when flag -> printfn "TRUE: %s" (ex.ToString()); 0
| ex when not flag -> printfn "FALSE: %s" (ex.ToString()); 1
let result2 = divide3 100 0 true
// This version shows the use of F# exceptions.
exception Error1 of string
exception Error2 of string * int
let function1 x y =
try
if x = y then raise (Error1("x"))
else raise (Error2("x", 10))
with
| Error1(str) -> printfn "Error1 %s" str
| Error2(str, i) -> printfn "Error2 %s %d" str i
function1 10 10
function1 9 2
Note
The try...with
construct is a separate expression from the try...finally
expression. Therefore, if your code requires both a with
block and a finally
block, you will have to nest the two expressions.
Note
You can use try...with
in async expressions, task expressions, and other computation expressions, in which case a customized version of the try...with
expression is used. For more information, see Async Expressions, Task Expressions, and Computation Expressions.