次の方法で共有


例外: try...finally 式

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...最後に、 式はカスタム実装を持つことができます。 詳細については、「 コンピュテーション式」を参照してください。

こちらも参照ください