16

これは、「C# 経由の CLR」、「効果的な C#」およびその他のリソースから IDisposable およびファイナライザーについて理解していることです。

  • IDisposable は、マネージド リソースとアンマネージド リソースを確定的にクリーンアップするためのものです。
  • アンマネージ リソース (ファイル ハンドルなど) を担当するクラスは、IDisposable を実装し、クライアント コードがインスタンスで Dispose() を呼び出さなくてもクリーンアップされることを保証するファイナライザーを提供する必要があります。
  • 管理対象リソースのみを担当するクラスは、ファイナライザーを実装しないでください。
  • ファイナライザーがある場合は、IDisposable を実装する必要があります (これにより、クライアント コードは正しいことを実行して Dispose() を呼び出すことができますが、ファイナライザーは忘れた場合のリソースのリークを防ぎます)。

上記のすべての理由を理解して同意しますが、これらのルールを破ることが理にかなっているシナリオが 1 つあります。それは、管理されていないリソース (特定のファイルへの単一アクセス ポイントを提供するなど) を担当するシングルトン クラスです。 )。

シングルトンインスタンスはアプリケーションの存続期間中存続する必要があり、クライアントコードが Dispose() を呼び出すと、詰め込まれているため、シングルトンに Dispose() メソッドを持つことは常に間違っていると思います。ただし、アプリケーションがアンロードされたときにファイナライザーがアンマネージ リソースをクリーンアップできるように、ファイナライザーが必要です。

したがって、IDisposable を実装しないファイナライザーを備えたシングルトン クラスを持つことは、合理的なことのように思えますが、このタイプの設計は、私が理解しているベスト プラクティスに反しています。

これは合理的なアプローチですか?そうでない場合、その理由と、優れた代替手段は何ですか?

4

6 に答える 6

6

オブジェクト指向の設計パターンとその結果は、オブジェクト指向言語であっても、常にすべての言語の決定に影響を与えるわけではありません。別の言語 (C++) ではなく、ある言語 (Smalltalk) で実装する方が簡単な古典的な設計パターンを確実に見つけることができます。

そうは言っても、シングルトンインスタンスはアプリケーションの最後にのみ破棄する必要があるという前提に同意するかどうかはわかりません。Singleton (またはDesign Patterns: Elements of reusable Object-Oriented Software ) について読んだデザイン パターンの説明には、これをこのパターンのプロパティとして言及しているものはありません。シングルトンは、クラスのインスタンスが常に 1 つだけ存在することを保証する必要があります。これは、アプリケーションが存在する限り存在しなければならないことを意味するものではありません。

実際には、アプリケーションの寿命のほとんどの間、多くのシングルトンが存在していると感じています。ただし、TCP 接続を使用してサーバーと通信するが、切断モードでも存在できるアプリケーションを考えてみましょう。接続時に、シングルトンで接続情報と接続の状態を維持する必要があります。切断されたら、同じシングルトンを保持したい場合や、シングルトンを破棄する場合があります。シングルトンを保持する方が理にかなっていると主張する人もいるかもしれませんが (私もその一人かもしれません)、設計パターン自体には、それを破棄することを妨げるものは何もありません。接続が再作成された場合、シングルトンをインスタンス化できます。繰り返しますが、その時点ではインスタンスが存在しないためです。

つまり、シングルトンが IDisposable を持つことが論理的であるシナリオを作成できます。

于 2009-01-21T00:49:07.757 に答える
5

アンマネージリソースがアプリケーションの終了時にのみ解放される場合は、プロセスのアンロードでこれを処理する必要があるため、ファイナライザーについて心配する必要はありません。

複数のアプリドメインがあり、アプリドメインのアンロードを処理する場合、これは考えられる問題の1つですが、気にする必要がない場合もあります。

次に、この設計はおそらく正しいことではないと言っています(そして、後で修正が難しくなるのは、実際には2つのインスタンスが必要であることがわかります)エントリポイントにオブジェクト(または遅延読み込みラッパーオブジェクト)を作成します誰が誰にそれを提供する責任があるかを明確にするために必要な場所にコードを渡します。その後、コードの残りの部分にほとんど影響を与えずに1つだけを使用するという決定を自由に変更できます(取得したものを使用します)与えられた)

于 2009-01-21T12:59:39.047 に答える
4

ファイナライザーが他のマネージド オブジェクトのメソッド (Dispose など) を呼び出さない限り、問題はありません。ファイナライズの順序は決定論的ではないことに注意してください。つまり、シングルトン オブジェクト Foo が破棄を必要とするオブジェクト Bar への参照を保持している場合、次のように確実に記述することはできません。

~Foo()
{
    Bar.Dispose();
}

ガベージ コレクターは既に Bar を収集している可能性があります。

OO グーの山に足を踏み入れる (つまり、戦争を開始する) 危険を冒して、シングルトンを使用する 1 つの代替手段は、静的クラスを使用することです。

于 2009-01-21T00:49:31.313 に答える
2

コード レビューの不満や FxCop の警告が表示される場合がありますが、IDisposable を使用せずにファイナライザーを実装しても、本質的に問題はありません。ただし、シングルトンでこれを行うことは、プロセスまたは AppDomain のティアダウンをキャプチャするための信頼できる方法ではありません。

主観的な設計アドバイスを提供するリスクがあります。オブジェクトが真にステートレスである場合は、静的クラスにします。ステートフルな場合は、なぜシングルトンなのか疑問に思います。可変グローバル変数を作成しています。アプリケーションの終了をキャプチャしようとしている場合は、メイン ループが終了したときに処理してください。

于 2009-01-21T01:07:29.497 に答える
0

ファイナライザーを使用してシングルトンを作成する場合は、おそらくそれへの静的参照がWeakReferenceである必要があります。これには、アクセサーのスレッドセーフを確保するために少し余分な作業が必要になりますが、誰も使用していないときにシングルトンをガベージコレクションできるようになります(後で誰かがGetInstance()メソッドを呼び出すと、新しいインスタンス)。静的な強力な参照が使用された場合、他に参照がなくても、シングルトンインスタンスは存続します。

于 2010-09-27T23:06:32.977 に答える
0

特定の状況へのシングルトンの適用性はさておき、

シングルトンを処分しても問題ないと思います。遅延インスタンス化と組み合わせると、リソースが一時的に必要ない場合はリソースを解放し、必要に応じて再取得することを意味します。

于 2009-01-21T13:47:32.990 に答える