リソースの管理: use キーワード (F#)
このトピックでは、use キーワードと using 関数について説明します。これらを使用して、リソースの初期化と解放を制御できます。
リソース
リソースという用語は、複数の方法で使用されます。リソースとは、アプリケーションが使用するデータ (文字列、グラフィックスなど) である場合もありますが、このコンテキストのリソースは、ソフトウェアやオペレーティング システムのリソースを指しています。たとえば、グラフィックス デバイス コンテキスト、ファイル ハンドル、ネットワーク接続とデータベース接続、待機ハンドルなどの同時実行オブジェクトなどです。アプリケーションがこれらのリソースを使用する場合は、オペレーティング システムや他のリソース プロバイダーからリソースを取得します。その後に、別のアプリケーションに提供できるように、リソースをプールに解放します。アプリケーションがリソースを解放して共通のプールに戻さないと、問題が発生します。
リソースの管理
アプリケーションのリソースを効率的かつ確実に管理するには、リソースを予測可能な方法で迅速に解放する必要があります。.NET Framework には IDisposable インターフェイスが用意されているため、この作業を簡単に行うことができます。IDisposable を実装する型には、適切にリソースを解放する Dispose メソッドがあります。アプリケーションを効率的に記述すると、限られたリソースを保持するオブジェクトが不要になったときに、Dispose が直ちに呼び出されることが保証されます。さいわい、ほとんどの .NET 言語では、この処理を簡単に行うためのサポートが提供されており、F# も例外ではありません。破棄のパターンをサポートする有用な言語構成要素が 2 つあります。use 束縛と using 関数です。
use 束縛
use キーワードの形式は、let 束縛の形式に似ています。
use value = expression
let 束縛と同じ機能が提供されるだけでなく、値がスコープの外に出ると、値の Dispose が呼び出されます。コンパイラによって値の null チェックが挿入されるため、値が null の場合には Dispose の呼び出しは試行されません。
次の例は、use キーワードを使用してファイルを自動的に閉じる方法を示しています。
open System.IO
let writetofile filename obj =
use file1 = File.CreateText(filename)
file1.WriteLine("{0}", obj.ToString() )
// file1.Dispose() is called implicitly here.
writetofile "abc.txt" "Humpty Dumpty sat on a wall."
[!メモ]
use はコンピュテーション式で使用できます。その場合は、use 式のカスタマイズされたバージョンを使用します。詳細については、「シーケンス (F#)」、「非同期ワークフロー (F#)」、および「コンピュテーション式 (F#)」を参照してください。
using 関数
using 関数は、次の形式になります。
using (expression1) function-or-lambda
using 式では、expression1 が破棄する必要があるオブジェクトを作成します。expression1 の結果 (破棄する必要があるオブジェクト) は、function-or-lambda への、value という引数になります。function-or-lambda は、expression1 によって生成された値に一致する型の 1 つの引数を受け取る関数、およびその型の引数を受け取るラムダ式のいずれかです。関数の実行が終了すると、ランタイムによって Dispose が呼び出され、リソースが解放されます (値が null の場合を除きます。この場合、Dispose の呼び出しは試行されません)。
次の例は、ラムダ式を使用した using 式を示しています。
open System.IO
let writetofile2 filename obj =
using (System.IO.File.CreateText(filename)) ( fun file1 ->
file1.WriteLine("{0}", obj.ToString() )
)
writetofile2 "abc2.txt" "The quick sly fox jumped over the lazy brown dog."
次の例は、関数を使用した using 式を示しています。
let printToFile (file1 : System.IO.StreamWriter) =
file1.WriteLine("Test output");
using (System.IO.File.CreateText("test.txt")) printToFile
この関数は、引数が既に適用されている関数である可能性があります。ドメイン スコープを追加するコード例を次に示します。この例では、文字列 XYZ が含まれるファイルを作成します。
let printToFile2 obj (file1 : System.IO.StreamWriter) =
file1.WriteLine(obj.ToString())
using (System.IO.File.CreateText("test.txt")) (printToFile2 "XYZ")
using 関数と use 束縛は、同じことを実現するほぼ同等の方法です。using キーワードを使用すると、Dispose を呼び出したときに、より効率的に制御できます。using を使用すると、関数またはラムダ式の最後で Dispose が呼び出され、use キーワードを使用すると、含まれているコード ブロックの最後で Dispose が呼び出されます。通常は、using 関数の代わりに use を使用する必要があります。