Exceptions: The try...with Expression
This topic describes the
try...with expression, the expression that is used for exception handling in the F# language.
try expression1 with | pattern1 -> expression2 | pattern2 -> expression3 ...
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
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
You can use a variety of patterns to filter on the exception type and other conditions; the options are summarized in the following table.
|:? 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.|
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
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.
You can use
try...with in asynchronous workflows and other computation expressions, in which case a customized version of the
try...with expression is used. For more information, see Asynchronous Workflows, and Computation Expressions.