このトピックでは、リソースの初期化と解放を制御できるキーワード use
と using
関数について説明します。
リソース
リソースという用語は、複数の方法で使用されます。 はい。リソースは、文字列、グラフィックスなど、アプリケーションが使用するデータにすることができますが、このコンテキストでは、 リソース はソフトウェアまたはオペレーティング システムのリソース (グラフィックス デバイス コンテキスト、ファイル ハンドル、ネットワークとデータベース接続、待機ハンドルなどのコンカレンシー オブジェクトなど) を参照します。 アプリケーションでこれらのリソースを使用するには、オペレーティング システムまたは他のリソース プロバイダーからリソースを取得した後、リソースをプールにリリースして、別のアプリケーションに提供できるようにする必要があります。 問題は、アプリケーションがリソースを共通プールに解放しない場合に発生します。
リソースの管理
アプリケーション内のリソースを効率的かつ責任を持って管理するには、リソースを迅速かつ予測可能な方法で解放する必要があります。 .NET Framework は、 System.IDisposable
インターフェイスを提供することでこれを行うのに役立ちます。
System.IDisposable
を実装する型には、リソースを正しく解放するSystem.IDisposable.Dispose
メソッドがあります。 適切に記述されたアプリケーションでは、限られたリソースを保持するオブジェクトが不要になったときに、 System.IDisposable.Dispose
がすぐに呼び出されることを保証します。 幸いなことに、ほとんどの .NET 言語では、これを簡単にするためのサポートが提供されており、F# も例外ありません。 dispose パターンをサポートする便利な言語コンストラクトには、 use
バインドと using
関数の 2 つがあります。
バインドを使用する
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
は最後にリリースされます。
注
コンピュテーション式では use
を使用できます。この場合、 use
式のカスタマイズされたバージョンが使用されます。 詳細については、「 シーケンス、 非同期式、 タスク式、 コンピュテーション式」を参照してください。
using Function
using
関数の形式は次のとおりです。
using
(expression1) function-or-lambda
using
式では、expression1 は破棄する必要があるオブジェクトを作成します。
expression1 (破棄する必要があるオブジェクト) の結果は、関数またはラムダに対する引数、値になります。これは、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 jumps 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
を使用する必要があります。
こちらも参照ください
.NET