1

オブジェクトを受け取り、それに対して何らかの処理を行うルーチンがあります。オブジェクトは、可変である場合とそうでない場合があります。

void CommandProcessor(ICommand command) {
    // do a lot of things
}

同じコマンド インスタンスがプロセッサでループ バックする可能性があります。それが起こると、事態は厄介になります。これらの再訪問者を検出し、処理されないようにしたいと考えています。問題は、オブジェクト自体を邪魔することなく、透過的に行う方法です。

ここに私が試したものがあります

  • にプロパティを追加しましBoolean Visited {get, set}ICommand

あるモジュールのロジックが他のモジュールに表示されるため、これは好きではありません。ShutdownCommand簿記ではなく、シャットダウンに関係しています。また、より多くを得ることを期待して、EatIceCreamCommand常に戻ってくる場合があります。False一部の変更不可能なオブジェクトには、setter に関する完全な問題があります。

  • 処理されたすべてのインスタンスのルックアップ テーブルを非公開で維持します。オブジェクトが最初に来るとき、リストに対してチェックします。

これも好きじゃない。(1) パフォーマンス。ルックアップ テーブルが大きくなります。インスタンスを一致させるには、ライナー検索を行う必要があります。(2)頼りにならないhashcode。オブジェクトは時々異なるハッシュコードを偽造する可能性があります。(3) オブジェクトをリストに保持すると、オブジェクトがガベージ コレクションされるのを防ぐことができます。

私のコードだけが見ることができる(ICommand の)インスタンスに、目に見えないマーカーを配置する方法が必要です。現在、呼び出しを区別していません。同じインスタンスが戻ってこないことを祈るばかりです。誰かがこの機能を実装するためのより良いアイデアを持っています..?

4

1 に答える 1

3

これが起こるのを論理的に止めることができないと仮定すると(ループを切り取ってみてください)、HashSetすでに見たコマンドのいくつかに行きます。

HashCodeオブジェクトがandの契約に違反している場合でもEquals(私はこれを最初の問題と見なします)、非仮想的に呼び出すためIEqualityComparer<ICommand>に使用する独自のオブジェクトを作成できます。このメソッドは、参照 ID をテストするだけです。そのため、コマンドがおよびをオーバーライドするかどうか、またはその方法を気にせずに、プールに個別のインスタンスが含まれます。System.Runtime.CompilerServices.RuntimeHelpers.GetHashCodeObject.GetHashCodeEqualsEqualsGetHashCode

それだけで、ゴミが溜まるという問題が残ります。プールを定期的にパージするオプションがない場合は、 (または.NET 4WeakReference<T>の非ジェネリッククラス) を使用して、オブジェクトの保持を回避できます。WeakReference次に、すべての「死んだ」弱い参照を頻繁に見つけて、それらの蓄積を防ぐことさえできます。IEqualityComparer<WeakReference<T>>(この場合、比較子は実際には、弱参照のターゲットを同一性のために比較します。)

特にエレガントではありませんが、それは設計に固有のものであると私は主張します-どこかで状態を変更するにはコマンドを処理する必要があり、不変オブジェクトは定義により状態を変更できないため、コマンドの外側の状態が必要です。ハッシュ セットは、そのためのかなり合理的なアプローチのように思えます。うまくいけば、あなたが言及した 3 つの問題すべてを回避する方法が明確になったことを願っています。

編集:私が考えていなかった1つのことは、を使用WeakReference<T>するとエントリを削除するのが難しくなることです-元の値がガベージコレクションされると、そのハッシュコードを見つけることができなくなります。HashSetまだ生きているエントリで新しいものを作成する必要があるかもしれません。または、コメントに記載されているように、独自の LRU キャッシュを使用します。

于 2013-06-15T08:12:12.213 に答える