例外: try...finally 式 (F#)

try...finally 式を使用すると、コード ブロックから例外がスローされる場合でも、クリーンアップ コードを実行できます。

try
   expression1
finally
   expression2

解説

try...finally 式を使用すると、expression1 の実行中に例外が生成されたかどうかにかかわらず、前にある構文の expression2 のコードを実行できます。

expression2 の型は、式全体の値には影響しません。例外が発生しなかった場合に返される型は、expression1 での最終的な値です。例外が発生した場合、値は返されません。制御フローは、呼び出し履歴の上位に進み、一致する次の例外ハンドラーに移動します。例外ハンドラーが見つからない場合は、プログラムが終了します。一致するハンドラーのコードが実行される前、またはプログラムが終了する前に、finally 分岐内のコードが実行されます。

次のコードは、try...finally 式の使用方法を示しています。

let divide x y =
   let stream : System.IO.FileStream = System.IO.File.Create("test.txt")
   let writer : System.IO.StreamWriter = new System.IO.StreamWriter(stream)
   try
      writer.WriteLine("test1");
      Some( x / y )
   finally
      writer.Flush()
      printfn "Closing stream"
      stream.Close()

let result =
  try
     divide 100 0
  with
     | :? System.DivideByZeroException -> printfn "Exception handled."; None

コンソールへの出力は次のようになります。

Closing stream
Exception handled.

出力に示されているように、外部例外が処理される前にストリームが閉じられており、test.txt ファイルにテキスト test1 が格納されています。これは、例外が発生したことによって制御が外部例外ハンドラーに移動した場合でも、バッファーがフラッシュされてディスクに書き込まれることを示しています。

try...with の構造は、try...finally の構造とは異なることに注意してください。したがって、コードに with ブロックと finally ブロックの両方を記述する必要がある場合には、次のコード例のように、この 2 つの構造を入れ子にする必要があります。

exception InnerError of string
exception OuterError of string

let function1 x y =
   try
     try
        if x = y then raise (InnerError("inner"))
        else raise (OuterError("outer"))
     with
      | InnerError(str) -> printfn "Error1 %s" str
   finally
      printfn "Always print this."


let function2 x y =
  try
     function1 x y
  with
     | OuterError(str) -> printfn "Error2 %s" str

function2 100 100
function2 100 10

シーケンス式と非同期ワークフローなどのコンピュテーション式のコンテキストでは、try...finally 式にカスタム実装を指定できます。詳細については、「コンピュテーション式 (F#)」を参照してください。

参照

関連項目

例外: try...with 式 (F#)

その他の技術情報

例外処理 (F#)