サーチ…


備考

  • IDisposableを実装しているクラスのクライアントは、オブジェクトの使用が終了したらDisposeメソッドを呼び出すようにしています。 CLRには、呼び出すDisposeメソッドのオブジェクトを直接検索するものは何もありません。

  • オブジェクトに管理されたリソースのみが含まれている場合は、ファイナライザを実装する必要はありません。独自のDisposeメソッドを実装するときにクラスが使用するすべてのオブジェクトに対してDisposeを呼び出すようにしてください。

  • 理想的には一度だけ呼び出す必要がありますが、クラスをDisposeへの複数の呼び出しに対して安全にすることをお勧めします。これは、クラスにprivate bool変数を追加し、 Disposeメソッドが実行されたときに値をtrueに設定することでtrueできます。

管理対象リソースのみを含むクラス

管理リソースとは、ランタイムのガベージコレクタが認識し管理しているリソースのことです。 BCLには、管理されていないリソースのラッパークラスであるSqlConnectionなど、多数のクラスが用意されています。これらのクラスは既にIDisposableインターフェイスを実装しています。コードを実行すると、そのコードをクリーンアップすることができます。

クラスにマネージリソースのみが含まれている場合は、ファイナライザを実装する必要はありません。

public class ObjectWithManagedResourcesOnly : IDisposable
{
    private SqlConnection sqlConnection = new SqlConnection();

    public void Dispose()
    {
        sqlConnection.Dispose();
    }
}

管理リソースと非管理リソースを持つクラス

ファイナライズでは管理対象リソースを無視することが重要です。ファイナライザは別のスレッド上で動作します。ファイナライザが実行されるまでに管理オブジェクトが存在しなくなる可能性があります。保護されたDispose(bool)メソッドの実装は、管理されたリソースがファイナライザから呼び出されたDisposeメソッドを持たないようにするための一般的な方法です。

public class ManagedAndUnmanagedObject : IDisposable
{
    private SqlConnection sqlConnection = new SqlConnection();
    private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
    private bool disposed;

    public void Dispose()
    {
        Dispose(true); // client called dispose
        GC.SuppressFinalize(this); // tell the GC to not execute the Finalizer
    }

    protected virtual void Dispose(bool disposeManaged)
    {
        if (!disposed)
        {
            if (disposeManaged)
            {
                if (sqlConnection != null)
                {
                    sqlConnection.Dispose();
                }
            }

            unmanagedHandle.Release();

            disposed = true;
        }
    }

    ~ManagedAndUnmanagedObject()
    {
        Dispose(false);
    }
}

IDisposable、Dispose

.NET Frameworkは、ティアダウンメソッドを必要とするタイプのインターフェイスを定義します。

public interface IDisposable
{
  void Dispose();
}

Dispose()は主に、アンマネージ参照などのリソースのクリーンアップに使用されます。ただし、他のリソースを管理していても強制的に廃棄すると便利です。 GCが最終的にデータベース接続をクリーンアップするのを待つのではなく、自分のDispose()実装で完了したことを確認することができます。

public void Dispose()
{
   if (null != this.CurrentDatabaseConnection)
   {
       this.CurrentDatabaseConnection.Dispose();
       this.CurrentDatabaseConnection = null;
   }
}

管理されていないポインタやwin32リソースなどのアンマネージリソースに直接アクセスする必要がある場合は、 SafeHandleを継承するクラスを作成し、そのクラスの規約/ツールを使用します。

管理されたリソースを持つ継承クラス

IDisposableを実装するクラスを作成してから、管理されたリソースも含むクラスを生成することは、かなり一般的です。 Disposeメソッドをvirtualキーワードでマークして、クライアントが所有するリソースをすべてクリーンアップできるようにすることをお勧めします。

public class Parent : IDisposable
{
    private ManagedResource parentManagedResource = new ManagedResource();

    public virtual void Dispose()
    {
        if (parentManagedResource != null)
        {
            parentManagedResource.Dispose();
        }
    }
}

public class Child : Parent
{
    private ManagedResource childManagedResource = new ManagedResource();

    public override void Dispose()
    {
        if (childManagedResource != null)
        {
            childManagedResource.Dispose();
        }
        //clean up the parent's resources
        base.Dispose();
    }
}

キーワードを使用して

オブジェクトがIDisposableインターフェイスを実装するとき、それはusing構文で作成することができます:

using (var foo = new Foo())
{
    // do foo stuff
} // when it reaches here foo.Dispose() will get called

public class Foo : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("dispose called");
    }
}

デモを見る

try/finallyブロックにsyntatic sugarusingます。上記の使用法は、おおよそ次のように解釈されます。

{
    var foo = new Foo();
    try
    {
        // do foo stuff
    }
    finally
    {
        if (foo != null)
            ((IDisposable)foo).Dispose();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow