4

こちらの回答を読んだ後、 IDisposableの実装を簡素化するために、クラスをシール済みとしてマークすることにしました。seal が IDisposable の実装に影響を与えるのはなぜですか (たとえばGC.SuppressFinalize(this);、呼び出す必要がないなど)? 何が起こっているのか説明してください。クラスを封印した理由を仲間の開発者に説明できる必要があります。

4

3 に答える 3

2

を実装するクラスがIDisposable封印されていない場合、派生クラスが に応答して何かを実行する必要がある可能性がありますDisposeが、基本クラスのアクションも実行するDispose必要があります。Disposeクラスが常に と同義である public メンバーを公開する場合IDisposable.Dispose、必要なセマンティクスは、パブリック仮想Disposeメソッドで暗黙的なインターフェイス実装を使用するだけで、C# で実現できます。

このアプローチには 2 つの問題があります。

  1. 親がパブリックな「Dispose」メソッドを公開する場合と公開しない場合では、派生クラスが異なるメソッドを使用する必要があります。public `Dispose` メソッドを公開していないクラスが公開している封印されていないクラスに継承されると、事態は非常に混乱する可能性があります。
  2. 一部のベース処理コードは、派生クラスの処理コードの前に実行する必要があり (たとえば、`Dispose` 試行の繰り返しを抑制するコード)、一部は後で実行する必要があります (例: `GC.SuppressFinalize()`)。これを実現する唯一の方法は、非仮想ラッパーで保護された仮想関数を呼び出すことです。ところで、Microsoft のラッパーは繰り返しの Dispose を適切に抑制しませんが、ラッパーはそのような抑制コードに適した唯一の場所であることに注意してください。

DisposeMicrosoftは、基本クラスがオーバーライドしないFinalizeが、派生クラスがFinalizeクリーンアップに使用する場合にそのパターンを使用することを意図しているように見えることに注意してください。それが意図されているかもしれませんが、その目的には適したパターンではありません。ごくわずかな例外を除いて、クリーンアップのためにのみオーバーライドする必要があるクラスは、 のFinalizeような簡単なクラスから派生したクラスだけですObject。クラスが を実装しているIDisposableがオーバーライドしていない場合Finalize、派生クラスがオーバーライドすべき唯一の目的は、呼び出されFinalizeた場合にアラームを鳴らすことFinalizeであり、その使用法についても議論の余地があります (より良いパターンは次のようになります:

クラスは何でも:IDisposable
{
  IDisposable DisposedStatusObject;
  // センチネル値として使用できる静的ダミー オブジェクト インスタンスを生成します
  // `IDisposable` である必要がありますが、実際にリソースを保持するべきではありません。

  static IDisposable DisposedStatusDisposed = new List<int>().GetEnumerator();

  public bool Disposed {get {return (DisposedStatusObject == DisposedStatusDisposed);} }

  なんでもいい()
  {
    DisposedStatusObject = 新しい DisposalAlarm(); // コンストラクタで最初に行うこと
  }
  ボイドディスポーズ()
  {
    IDisposable prevStatus;
    prevStatus = Interlocked.Exchange(DisposedStatus, DisposedStatusDisposed);
    if (prevStatus != DisposedStatusDisposed)
    {
      破棄 (真);
      prevStatus.Dispose();
    }
  }
}

クラスは、メソッドが最初に呼び出されずにメソッドが呼び出された場合にアラームを鳴らすDisposalAlarm()オーバーライドされたメソッドを持つクラスであると見なされます。のメソッドは、派生クラスのメソッドが適切に返された場合、アラームがキャンセルされることを保証します。のインスタンスに抑制されていないファイナライザーがある場合、そのファイナライザーが実行されるか抑制されるまで、直接または間接的な参照を保持するすべてのものを保持する必要があることに注意してください。対照的に、オブジェクトを追加しても、 の寿命は延長されません。Finalize()Finalize()Dispose()DisposewhateverwhateverwhateverDisposalAlarmwhatever

于 2012-06-13T23:30:52.793 に答える
1

封印されたクラスは基本クラスとして使用されることを意図していませんが、封印されていないクラスは使用されます。したがって、違いがあります。封印されていないクラスは、派生クラスDispose()が独自に実装する方法を提供する必要がありますが、封印されたクラスは拡張できないため、この責任はありません。

于 2012-06-13T22:39:28.327 に答える
1

クラスを作成するsealedということは、そこから派生したクラスが存在できないことを意味します。つまり、 の実装でIDisposableは、派生クラスの動作 (または誤動作) を考慮する必要はありません。

于 2012-06-13T22:38:13.407 に答える