Dispose パターンDispose Pattern

すべてのプログラムは、それらの実行の進行中にメモリ、システムのハンドル、またはデータベース接続など、1 つまたは複数のシステム リソースを取得します。All programs acquire one or more system resources, such as memory, system handles, or database connections, during the course of their execution. 開発者は、取得し、使用後に解放する必要があるためには、このようなシステム リソースを使用する場合は注意が必要があります。Developers have to be careful when using such system resources, because they must be released after they have been acquired and used.

CLR は、自動メモリ管理のサポートを提供します。The CLR provides support for automatic memory management. マネージ メモリ (c# 演算子を使用して割り当てられたメモリnew) 明示的に解放する必要はありません。Managed memory (memory allocated using the C# operator new) does not need to be explicitly released. ガベージ コレクター (GC) によって自動的に解放されます。It is released automatically by the garbage collector (GC). これにより、開発者は、メモリを解放する難しい面倒な作業を解放し、.NET Framework によって提供される画期的な生産性向上のための主な理由の 1 つです。This frees developers from the tedious and difficult task of releasing memory and has been one of the main reasons for the unprecedented productivity afforded by the .NET Framework.

残念ながら、マネージ メモリは、さまざまな種類のシステム リソースの 1 つです。Unfortunately, managed memory is just one of many types of system resources. ただし、マネージ メモリ以外のリソースは明示的に解放する必要あるし、アンマネージ リソースと呼びます。Resources other than managed memory still need to be released explicitly and are referred to as unmanaged resources. GC が具体的には想定していません、このようなアンマネージ リソースを管理するには、開発者の手にアンマネージ リソースを管理する責任があることを意味します。The GC was specifically not designed to manage such unmanaged resources, which means that the responsibility for managing unmanaged resources lies in the hands of the developers.

CLR では、アンマネージ リソースを解放するときにいくつかのヘルプを提供します。The CLR provides some help in releasing unmanaged resources. System.Object 仮想メソッドを宣言Finalize(ファイナライザーとも呼ばれます) 前に、オブジェクトのメモリ GC によって解放され、アンマネージ リソースを解放するをオーバーライドすることができます、GC によって呼び出されます。System.Object declares a virtual method Finalize (also called the finalizer) that is called by the GC before the object’s memory is reclaimed by the GC and can be overridden to release unmanaged resources. ファイナライザーをオーバーライドする型は、ファイナライズ可能な型と呼ばれます。Types that override the finalizer are referred to as finalizable types.

ファイナライザーは、一部のクリーンアップのシナリオで効果的なは、2 つの重要な欠点があります。Although finalizers are effective in some cleanup scenarios, they have two significant drawbacks:

  • ファイナライザーは、GC では、オブジェクトがコレクションの対象となることが検出された場合に呼び出されます。The finalizer is called when the GC detects that an object is eligible for collection. これは、不定一定時間、リソースが今後不要後に行われます。This happens at some undetermined period of time after the resource is not needed anymore. 開発者がでしたまたはリソースとリソースが実際には、ファイナライザーで解放ときの時刻をリリースする場合の間の遅延が多く不足しているリソース (が簡単に不足したりリソース) を取得するプログラムでもは許容できない可能性があります。リソースの使用 (大規模なアンマネージ メモリ バッファーなど) に保持するコストのかかるがである場合。The delay between when the developer could or would like to release the resource and the time when the resource is actually released by the finalizer might be unacceptable in programs that acquire many scarce resources (resources that can be easily exhausted) or in cases in which resources are costly to keep in use (e.g., large unmanaged memory buffers).

  • CLR は、ファイナライザーを呼び出す必要がある、ときに、次は、ガベージ コレクション (コレクション間で実行するファイナライザー) のラウンドするまで、オブジェクトのメモリのコレクションを延期にする必要があります。When the CLR needs to call a finalizer, it must postpone collection of the object’s memory until the next round of garbage collection (the finalizers run between collections). これは、オブジェクトのメモリ (およびを参照してすべてのオブジェクト) は時間の長い期間に解放されないことを意味します。This means that the object’s memory (and all objects it refers to) will not be released for a longer period of time.

そのため、ファイナライザーでのみ証明書利用者できない可能性があります、不足しているリソースを処理する場合、可能な限り早くアンマネージ リソースを解放する必要がある場合、多くのシナリオで、または高パフォーマンスの高いシナリオで適切な GC の追加のオーバーヘッドファイナライズは許容されません。Therefore, relying exclusively on finalizers might not be appropriate in many scenarios when it is important to reclaim unmanaged resources as quickly as possible, when dealing with scarce resources, or in highly performant scenarios in which the added GC overhead of finalization is unacceptable.

フレームワークは、提供、System.IDisposableインターフェイスを手動で必要でないとすぐに、アンマネージ リソースを解放することを開発者に提供するために実装する必要があります。The Framework provides the System.IDisposable interface that should be implemented to provide the developer a manual way to release unmanaged resources as soon as they are not needed. 用意されています、GC.SuppressFinalizeするように、GC が知ることができるメソッド オブジェクトの破棄が手動で必要としない、完了するをその場合、オブジェクトのメモリを再要求できる前です。It also provides the GC.SuppressFinalize method that can tell the GC that an object was manually disposed of and does not need to be finalized anymore, in which case the object’s memory can be reclaimed earlier. 実装する型、IDisposableインターフェイスが破棄可能な型と呼びます。Types that implement the IDisposable interface are referred to as disposable types.

Dispose パターンは、使用状況およびファイナライザーの実装を標準化するためのものとIDisposableインターフェイスです。The Dispose Pattern is intended to standardize the usage and implementation of finalizers and the IDisposable interface.

パターンの主要な動機がの実装の複雑さを軽減するには、FinalizeDisposeメソッドです。The main motivation for the pattern is to reduce the complexity of the implementation of the Finalize and the Dispose methods. 複雑さのメソッドがいくつかのコード パスが (相違点は後で説明) を共有することに由来します。The complexity stems from the fact that the methods share some but not all code paths (the differences are described later in the chapter). さらに、履歴上の理由から決定論的リソース管理のための言語サポートの進化に関連するパターンの一部の要素があります。In addition, there are historical reasons for some elements of the pattern related to the evolution of language support for deterministic resource management.

✓ DO 破棄可能な型のインスタンスを含む型で、基本的な Dispose パターンを実装します。✓ DO implement the Basic Dispose Pattern on types containing instances of disposable types. 参照してください、 Dispose の基本的なパターン基本的なパターンの詳細セクションです。See the Basic Dispose Pattern section for details on the basic pattern.

型が破棄可能なその他のオブジェクトの有効期間を担当する場合は、開発者はすぎる、それらを破棄する方法を必要があります。If a type is responsible for the lifetime of other disposable objects, developers need a way to dispose of them, too. 使用して、コンテナーのDispose実現する便利な方法です。Using the container’s Dispose method is a convenient way to make this possible.

✓ DO 基本の Dispose パターンを実装し、保持しているリソースを明示的に解放できる必要があると、ファイナライザーがない型でファイナライザーを用意します。✓ DO implement the Basic Dispose Pattern and provide a finalizer on types holding resources that need to be freed explicitly and that do not have finalizers.

たとえば、アンマネージ メモリ バッファーを格納する型で、パターンを実装する必要があります。For example, the pattern should be implemented on types storing unmanaged memory buffers. ファイナライズ可能な型ファイナライザーを実装する関連のガイドラインについて説明します。The Finalizable Types section discusses guidelines related to implementing finalizers.

✓ CONSIDER 基本の Dispose パターンを実装するクラスでのリソースとアンマネージ自体を保持しないことや、破棄可能なオブジェクトは、実行のサブタイプをされている可能性がします。✓ CONSIDER implementing the Basic Dispose Pattern on classes that themselves don’t hold unmanaged resources or disposable objects but are likely to have subtypes that do.

これの好例が、System.IO.Streamクラスです。A great example of this is the System.IO.Stream class. 抽象基本クラスのすべてのリソースを保持しませんが、そのサブクラスのほとんどは、このため、このパターンを実装します。Although it is an abstract base class that doesn’t hold any resources, most of its subclasses do and because of this, it implements this pattern.

基本の Dispose パターンBasic Dispose Pattern

基本的なパターンの実装では、実装では、System.IDisposableインターフェイスを宣言する、Dispose(bool)間で共有するすべてのリソースのクリーンアップ ロジックを実装するメソッド、Disposeメソッドと省略可能な終了します。The basic implementation of the pattern involves implementing the System.IDisposable interface and declaring the Dispose(bool) method that implements all resource cleanup logic to be shared between the Dispose method and the optional finalizer.

次の例は、基本的なパターンの簡単な実装を示しています。The following example shows a simple implementation of the basic pattern:

public class DisposableResourceHolder : IDisposable {  

    private SafeHandle resource; // handle to a resource  

    public DisposableResourceHolder() {  
        this.resource = ... // allocates the resource  
    }  

    public void Dispose() {  
        Dispose(true);  
        GC.SuppressFinalize(this);  
    }  

    protected virtual void Dispose(bool disposing) {  
        if (disposing) {  
            if (resource!= null) resource.Dispose();  
        }  
    }  
}  

ブール型パラメーターdisposingから呼び出されたメソッドであるかどうかを示す、IDisposable.Dispose実装またはファイナライザーからです。The Boolean parameter disposing indicates whether the method was invoked from the IDisposable.Dispose implementation or from the finalizer. Dispose(bool)実装は、その他の参照オブジェクト (上記のサンプルのリソース フィールドなど) にアクセスする前に、パラメーターを確認する必要があります。The Dispose(bool) implementation should check the parameter before accessing other reference objects (e.g., the resource field in the preceding sample). このようなオブジェクトからこのメソッドが呼び出された場合にのみアクセスする必要があります、IDisposable.Dispose実装 (ときに、disposingパラメーターが true に等しい)。Such objects should only be accessed when the method is called from the IDisposable.Dispose implementation (when the disposing parameter is equal to true). メソッドがファイナライザーから呼び出された場合 (disposingは false)、その他のオブジェクトにアクセスしないようにします。If the method is invoked from the finalizer (disposing is false), other objects should not be accessed. オブジェクトが予期しない順序で完了し、ため、またはその依存関係のいずれかが既にが完了することです。The reason is that objects are finalized in an unpredictable order and so they, or any of their dependencies, might already have been finalized.

また、このセクションでは、Dispose パターンが実装していません基数を持つクラスに適用されます。Also, this section applies to classes with a base that does not already implement the Dispose Pattern. オーバーライドするだけで既にパターンを実装するクラスから継承している場合、Dispose(bool)追加のリソースのクリーンアップ ロジックを提供します。If you are inheriting from a class that already implements the pattern, simply override the Dispose(bool) method to provide additional resource cleanup logic.

✓ DO 宣言、protected virtual void Dispose(bool disposing)アンマネージ リソースの解放に関連するすべてのロジックを集中管理するメソッド。✓ DO declare a protected virtual void Dispose(bool disposing) method to centralize all logic related to releasing unmanaged resources.

すべてのリソースのクリーンアップは、このメソッドで発生する必要があります。All resource cleanup should occur in this method. 両方のファイナライザーからメソッドを呼び出したとIDisposable.Disposeメソッドです。The method is called from both the finalizer and the IDisposable.Dispose method. パラメーターは、ファイナライザーの内部から呼び出されている場合は false になります。The parameter will be false if being invoked from inside a finalizer. 終了処理中に実行されるコードがファイナライズ可能なその他のオブジェクトにアクセスしていないことを確認することを使用してください。It should be used to ensure any code running during finalization is not accessing other finalizable objects. ファイナライザーの実装の詳細については、次のセクションで説明します。Details of implementing finalizers are described in the next section.

protected virtual void Dispose(bool disposing) {  
    if (disposing) {  
        if (resource!= null) resource.Dispose();  
    }  
}  

✓ DO 実装、IDisposableだけ呼び出すことによってインターフェイスDispose(true)続くGC.SuppressFinalize(this)です。✓ DO implement the IDisposable interface by simply calling Dispose(true) followed by GC.SuppressFinalize(this).

呼び出しSuppressFinalize場合にのみ発生Dispose(true)が正常に実行します。The call to SuppressFinalize should only occur if Dispose(true) executes successfully.

public void Dispose(){  
    Dispose(true);  
    GC.SuppressFinalize(this);  
}  

X DO NOT パラメーターなしで行うDispose仮想メソッドです。X DO NOT make the parameterless Dispose method virtual.

Dispose(bool)メソッドであるサブクラスによってオーバーライドする必要があります。The Dispose(bool) method is the one that should be overridden by subclasses.

// bad design  
public class DisposableResourceHolder : IDisposable {  
    public virtual void Dispose() { ... }  
    protected virtual void Dispose(bool disposing) { ... }  
}  

// good design  
public class DisposableResourceHolder : IDisposable {  
    public void Dispose() { ... }  
    protected virtual void Dispose(bool disposing) { ... }  
}  

X DO NOT のすべてのオーバー ロードを宣言、Dispose以外のメソッドDispose()Dispose(bool)です。X DO NOT declare any overloads of the Dispose method other than Dispose() and Dispose(bool).

Dispose このパターンを体系化し、実装、ユーザー、およびコンパイラの間での混乱を回避するために予約語を考慮ください。Dispose should be considered a reserved word to help codify this pattern and prevent confusion among implementers, users, and compilers. 一部の言語は、特定の種類に自動的にこのパターンを実装することもできます。Some languages might choose to automatically implement this pattern on certain types.

✓ DO を許可する、Dispose(bool)に複数回呼び出されるメソッド。✓ DO allow the Dispose(bool) method to be called more than once. メソッドは、最初の呼び出し後に何もすることもできます。The method might choose to do nothing after the first call.

public class DisposableResourceHolder : IDisposable {  

    bool disposed = false;  

    protected virtual void Dispose(bool disposing) {  
        if (disposed) return;  
        // cleanup  
        ...  
        disposed = true;  
    }  
}  

X AVOID 内から例外をスローしてDispose(bool)されている重要な状況で格納しているプロセスが破損している場合を除き (リークを一貫性のない共有状態などです。)。X AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).

ユーザーが期待するへの呼び出しDispose例外は発生しません。Users expect that a call to Dispose will not raise an exception.

場合Dispose例外を発生させる可能性があります、これ以上の finally ブロックのクリーンアップ ロジックは実行されません。If Dispose could raise an exception, further finally-block cleanup logic will not execute. この問題を回避する、ユーザーが すべての呼び出しをラップする必要がありますDispose(内で、finally ブロック!)、try ブロックで非常に複雑なクリーンアップ ハンドラーにつながります。To work around this, the user would need to wrap every call to Dispose (within the finally block!) in a try block, which leads to very complex cleanup handlers. 実行している場合、Dispose(bool disposing)メソッド、破棄が false の場合に例外がスローされません。If executing a Dispose(bool disposing) method, never throw an exception if disposing is false. これによりファイナライザー コンテキスト内で実行されている場合、プロセスが終了されます。Doing so will terminate the process if executing inside a finalizer context.

✓ DO スロー、ObjectDisposedExceptionオブジェクトが破棄された後は使用できませんのすべてのメンバーからです。✓ DO throw an ObjectDisposedException from any member that cannot be used after the object has been disposed of.

public class DisposableResourceHolder : IDisposable {  
    bool disposed = false;  
    SafeHandle resource; // handle to a resource  

    public void DoSomething() {  
        if (disposed) throw new ObjectDisposedException(...);  
        // now call some native methods using the resource   
        ...  
    }  
    protected virtual void Dispose(bool disposing) {  
        if (disposed) return;  
        // cleanup  
        ...  
        disposed = true;  
    }  
}  

✓ CONSIDER メソッドを提供するClose()に加え、Dispose()領域での一般的な用語が閉じるかどうかは。✓ CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area.

これを行うことが重要を作成すること、Close実装と同じDisposeを実装することを検討してください、IDisposable.Disposeメソッドに明示的にします。When doing so, it is important that you make the Close implementation identical to Dispose and consider implementing the IDisposable.Dispose method explicitly.

public class Stream : IDisposable {  
    IDisposable.Dispose() {  
        Close();  
    }  
    public void Close() {  
        Dispose(true);  
        GC.SuppressFinalize(this);  
    }  
}  

ファイナライズ可能な型Finalizable Types

ファイナライズ可能な型はファイナライザーをオーバーライドして、終了コードのパスを提供することによって、基本的な Dispose パターンを拡張する型は、Dispose(bool)メソッドです。Finalizable types are types that extend the Basic Dispose Pattern by overriding the finalizer and providing finalization code path in the Dispose(bool) method.

ファイナライザーは、実行中に、システムの状態に関する (通常は有効な) 仮定をすることはできませんので、主に正しく実装する非常に困難です。Finalizers are notoriously difficult to implement correctly, primarily because you cannot make certain (normally valid) assumptions about the state of the system during their execution. 慎重に検討には、次のガイドラインを考慮する必要があります。The following guidelines should be taken into careful consideration.

ガイドラインの一部がしないようにだけに適用されるに注意してください、Finalizeメソッド、ファイナライザーからすべてのコードが呼び出されます。Note that some of the guidelines apply not just to the Finalize method, but to any code called from a finalizer. つまり、ロジック内で実行される場合は、基本的な Dispose パターン以前に定義した、Dispose(bool disposing)ときに、disposingパラメーターを false にします。In the case of the Basic Dispose Pattern previously defined, this means logic that executes inside Dispose(bool disposing) when the disposing parameter is false.

基本クラス既にファイナライズ可能な基本的な Dispose パターンを実装場合、する必要がありますはオーバーライドFinalizeもう一度です。If the base class already is finalizable and implements the Basic Dispose Pattern, you should not override Finalize again. 代わりにだけをオーバーライドする、Dispose(bool)追加のリソースのクリーンアップ ロジックを提供します。You should instead just override the Dispose(bool) method to provide additional resource cleanup logic.

次のコードでは、ファイナライズ可能な型の例を示します。The following code shows an example of a finalizable type:

public class ComplexResourceHolder : IDisposable {  

    private IntPtr buffer; // unmanaged memory buffer  
    private SafeHandle resource; // disposable handle to a resource  

    public ComplexResourceHolder() {  
        this.buffer = ... // allocates memory  
        this.resource = ... // allocates the resource  
    }  

    protected virtual void Dispose(bool disposing) {  
            ReleaseBuffer(buffer); // release unmanaged memory  
        if (disposing) { // release other disposable objects  
            if (resource!= null) resource.Dispose();  
        }  
    }  

    ~ComplexResourceHolder() {
        Dispose(false);  
    }  

    public void Dispose() {
        Dispose(true);  
        GC.SuppressFinalize(this);  
    }  
}  

X AVOID ファイナライズ可能な型を作成します。X AVOID making types finalizable.

いかなる場合においてもいると思われるファイナライザーが必要な慎重に検討します。Carefully consider any case in which you think a finalizer is needed. 実際のパフォーマンスとコードの両方の複雑さの観点からのファイナライザーを持つインスタンスに関連付けられているコスト。There is a real cost associated with instances with finalizers, from both a performance and code complexity standpoint. などのリソースのラッパーを使用して必要に応じてSafeHandleを可能な場合は、アンマネージ リソースをカプセル化する、その場合、ファイナライザーが不要になるラッパーが独自のリソースのクリーンアップを行うためです。Prefer using resource wrappers such as SafeHandle to encapsulate unmanaged resources where possible, in which case a finalizer becomes unnecessary because the wrapper is responsible for its own resource cleanup.

X DO NOT ファイナライズ可能な値の型を作成します。X DO NOT make value types finalizable.

実際には参照型のみが、CLR によって終了取得され、値の型でファイナライザーを配置するあらゆる試みは無視されるためです。Only reference types actually get finalized by the CLR, and thus any attempt to place a finalizer on a value type will be ignored. C# および C++ コンパイラは、この規則を強制します。The C# and C++ compilers enforce this rule.

✓ DO 型は独自のファイナライザーがない、アンマネージ リソースを解放する必要がある場合の種類をファイナライズようにします。✓ DO make a type finalizable if the type is responsible for releasing an unmanaged resource that does not have its own finalizer.

ファイナライザーを実装する場合を呼び出すだけDispose(false)内のすべてのリソースのクリーンアップ ロジックを配置し、Dispose(bool disposing)メソッドです。When implementing the finalizer, simply call Dispose(false) and place all resource cleanup logic inside the Dispose(bool disposing) method.

public class ComplexResourceHolder : IDisposable {  

    ~ComplexResourceHolder() {
        Dispose(false);  
    }  

    protected virtual void Dispose(bool disposing) {
        ...  
    }  
}  

✓ DO ファイナライズ可能な型で、基本的な Dispose パターンを実装します。✓ DO implement the Basic Dispose Pattern on every finalizable type.

これにより、型のユーザーは明示的にファイナライザーが担当する同じリソースの確定的なクリーンアップを実行することを意味します。This gives users of the type a means to explicitly perform deterministic cleanup of those same resources for which the finalizer is responsible.

X DO NOT こと、が既に終了されている重大なリスクがあるため、ファイナライザーのコード パスに、ファイナライズ可能なオブジェクトにアクセスします。X DO NOT access any finalizable objects in the finalizer code path, because there is significant risk that they will have already been finalized.

たとえば、別のファイナライズ可能なオブジェクト B を参照しているファイナライズ可能なオブジェクト A 確実にでは使用できません B A のファイナライザー、またはその逆です。For example, a finalizable object A that has a reference to another finalizable object B cannot reliably use B in A’s finalizer, or vice versa. ファイナライザーは、(重要な終了処理の弱い順序保証) する場合を除きランダムな順序で呼び出されます。Finalizers are called in a random order (short of a weak ordering guarantee for critical finalization).

また、アプリケーション ドメインのアンロード中またはプロセスの終了中に、静的変数に格納されているオブジェクトは特定の時点で収集取得こともあります。Also, be aware that objects stored in static variables will get collected at certain points during an application domain unload or while exiting the process. ファイナライズ可能なオブジェクト (または静的変数に格納された値を使用する静的メソッドを呼び出す) を参照する静的変数ができない可能性がありますにアクセスする場合は安全なEnvironment.HasShutdownStartedは true を返します。Accessing a static variable that refers to a finalizable object (or calling a static method that might use values stored in static variables) might not be safe if Environment.HasShutdownStarted returns true.

✓ DO ように、Finalize保護されているメソッド。✓ DO make your Finalize method protected.

C#、C++、および VB.NET の開発者は、このガイドラインを適用すると、コンパイラに役立つため、これについて心配する必要はありません。C#, C++, and VB.NET developers do not need to worry about this, because the compilers help to enforce this guideline.

X DO NOT システムに重大な障害を除く、ファイナライザーのロジックから使用すると、例外のエスケープします。X DO NOT let exceptions escape from the finalizer logic, except for system-critical failures.

ファイナライザーから例外をスローすると場合、CLR はシャット ダウンの時点で .NET Framework version 2.0)、プロセス全体を実行して適切な方法で解放されてからのリソースから他のファイナライザーを防止します。If an exception is thrown from a finalizer, the CLR will shut down the entire process (as of .NET Framework version 2.0), preventing other finalizers from executing and resources from being released in a controlled manner.

✓ CONSIDER を作成して、重要なファイナライズ可能なオブジェクトを使用して (を含む型階層を持つ型CriticalFinalizerObject) の状況でファイナライザーどうしても必要があります実行発生した場合でも強制アプリケーション ドメインのアンロード スレッド中止します。✓ CONSIDER creating and using a critical finalizable object (a type with a type hierarchy that contains CriticalFinalizerObject) for situations in which a finalizer absolutely must execute even in the face of forced application domain unloads and thread aborts.

部分 © 2005、2009 Microsoft Corporation します。All rights reserved.Portions © 2005, 2009 Microsoft Corporation. All rights reserved.

ピアソン教育, Inc. からのアクセス許可によって検出Framework デザイン ガイドライン: 規則、表現方法、および再利用可能な .NET ライブラリを第 2 版パターンは Cwalina と Brad Abrams、2008 年 10 月 22 日で発行されました。Microsoft Windows 開発シリーズの一部として、Addison-wesley Professional。Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, published Oct 22, 2008 by Addison-Wesley Professional as part of the Microsoft Windows Development Series.

関連項目See Also

IDisposable.Dispose
Object.Finalize
フレームワーク デザインのガイドラインFramework Design Guidelines
共通デザイン パターンCommon Design Patterns
ガベージ コレクションGarbage Collection