2

最近、Dispose() 機能を実装する必要があり、1 行のメソッド、2 行のメソッド、およびより包括的なメソッドに遭遇しました。

1行のメソッド/関数は単に「context.Dispose」のようなものを呼び出すだけですが、私が選んだメソッドは次のとおりです:

    bool _disposed = false;

    public void Dispose(bool disposing)
    {
        if (!_disposed && disposing)
        {
            _context.Dispose();
        }
        _disposed = true;
    }

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

この構文は、単に Dispose() が複数回呼び出されるのを止めるためのものですか?

4

3 に答える 3

4

あなたが投稿したのは部分的にDispose Patternです。誰かが指摘したようDispose(false)に、ファイナライザー (「デストラクタ」) に対応するものがあるはずです。アンマネージ リソースを破棄するには、ファイナライザーを使用する必要があります。処理するアンマネージ リソースがない場合 (つまり、 is のときに何もする必要がない場合disposing) false、 は必要Dispose(false)ないため、ファイナライザーは必要ありません。これは、それDispose(true)が唯一のパスであることを意味するため、不要Dispose (bool)で (したがって、Dispose パターンを実装する必要はありません)、本体を移動してDispose(および のチェックを削除しdisposing)、 を実装するだけDisposeです。例えば:

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

独自のファイナライザー (デストラクタ) を実装しないクラスは、ファイナライザー リストに追加されないため、 を呼び出す必要はありませんGC.SuppressFinalize

通常、クラスを作成する場合はこれで十分です。ただし、このパターンを実装するクラスから派生できる場合もあります。その場合、そのサポートをクラスに実装する必要があります (オーバーライドDispose(bool)して、管理対象リソースのdisposingチェックを行いますDispose)。基本クラスは で aを実装IDisposableして呼び出すため、自分で実装する必要はありませんが、で基本クラスを呼び出す必要があります。例えば:virtual Dispose(bool)Dispose()Dispose()Dispose(bool)Dispose(bool)

protected override void Dispose(bool disposing)
{
    if(disposing) _context.Dispose();
    base.Dispose(disposing);
}

GC.SuppressFinalize()ベースを呼び出していて、Dispose パターンが実装されている場合は、既に実行しているため、呼び出す必要もありません。

必要に応じて、すべてを行うことができますdisposed。ただし、マルチディスポーズのバグが隠されていることがわかりました。

于 2012-08-26T14:28:42.587 に答える
2

それはパターンのほんの一部です。ここで欠落している他の部分はDispose(false)、ファイナライザーによって呼び出される部分です。

_disposed状態フラグを使用して、メソッドをチェックしてスローすることもできますObjectDisposedExceptions

全パターンはこちら

Jon Skeet はここで良い情報を提供しています。IMO このパターンは、管理されていないリソースも持っていない限り、ほとんどの状況でやり過ぎです。そうでない場合は、管理されたリソースを破棄GC.SuppressFinalizeし、Dispose()インターフェイスの実装に入れます。_disposedスローする場合にのみフラグを使用してくださいObjectDisposedExceptions

于 2012-08-26T13:02:38.070 に答える
1

クラスのニーズに基づいて、次の 2 つの形式の破棄を使用します。

方法 1 (マネージド リソースとアンマネージド リソース、または派生クラスを含むクラスの場合):

class ClassHavingManagedAndUnManagedCode : IDiposable
    {
        private volatile bool _disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    //Do managed disposing here.
                }

                //Do unmanaged disposing here.
            }
        }

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

            _disposed = true;
        }

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

方法 2 (管理対象リソースのみのクラス / 封印クラス / 子クラスを持たないクラスの場合):

    class ClassHavingOnlyManagedCode  : IDiposable
    {
        private volatile bool _disposed = false;

        public void Dispose()
        {
            if (!_disposed)
            {
                //Dispose managed objects.
                _disposed = true;
            }
        }
    }

ClassHavingManagedAndUnManagedCode の子クラスはすべて、保護された破棄メソッド パターンに従い、Dispose メソッドの最後で base.Dispose を呼び出す必要があります。

また、クラス インスタンスが既に破棄されている場合は、ObjectDisposedException をスローするメソッド /check を使用して、すべてのパブリック メソッド (少なくとも破棄されたメンバーを使用しているメソッド) を保護します。

アンマネージ リソースがない場合でも、FxCop は常に ClassHavingManagedAndUnManagedCode 形式の Dispose を実装するように求めます。

于 2012-08-26T13:11:08.873 に答える