1

WeakReference私は「TheC#Language」、第4版を読んでいます、それは話しWeak Event Patternます:

CHRISTIAN NAGEL:メモリリークは、イベントの誤った使用に起因することがよくあります。クライアントオブジェクトがイベントにアタッチされているが、イベントから切り離されておらず、クライアントオブジェクトへの参照が使用されなくなった場合でも、パブリッシャーによる参照が残っているため、クライアントオブジェクトをガベージコレクターが再利用することはできません。これは、(1)クライアントオブジェクトが使用されなくなったときにイベントをデタッチする、(2)デリゲートを保持するクラスを使用する、addおよびremoveアクセサーのカスタム実装、または(3) IWeakEventListenerでWPFによって使用されるイベントによって回避できます。インターフェース。WeakReferenceWeak Event pattern

ここで疑問があります。オプション「(2)WeakReference」は、「オプション(1)イベントの明示的なデタッチ」と比較して、まったく便利ではありません。これは、を使用すると、との両方をWeakReference明示的に呼び出す必要があるためです。addremove

そうしないと、イベントハンドラーのオブジェクトの1つがnullに割り当てられた場合でも、「孤立した」オブジェクトはイベントに応答します。これにより、予期しない動作が発生します。

注:WeakReferenceイベントハンドラーのオブジェクトがイベントパブリッシャーオブジェクトの影響を受けないようにする方法でのみ、ガベージコレクションを支援します。WeakReferenceイベントハンドラオブジェクトにガベージコレクションを強制しません。

同様の問題は、弱いイベントパターンにも当てはまります。

これは少し抽象的かもしれません。例として、Josh Smithのメディエーターパターン(http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/)を取り上げます。

public class Mediator //...
{
  public void Register(object message, Action<object> callback)
  {
    // notice: Mediator has no Unregister method
  }
  public void NotifyColleagues(object message, object parameter)
  {
    // ...
  }
}
public class ObjectA //...
{
  public string ObjectAText
  {
    get { return _objectAText; }
    set
    {
      //...
      _mediator.NotifyColleagues(MediatorMessages.ObjectASaidSomething, _objectAText);
    }
  }
}
public class ObjectB //...
{
  //...
  public ObjectB(Mediator mediator)
  {
    //...
    _mediator.Register(
      MediatorMessages.ObjectASaidSomething,
      param =>
      {
        // handling event ObjectASaidSomething
      });
  }
}

私たちが持っている場合

ObjectA objectA = new ObjectA();
ObjectB objectB1st = new objectB();
objectA.ObjectAText = "John"; // objectB1st will respond to this event.

objectB1st = null; // due to delay of garbage collection, the object is actually still in memory

ObjectB objectB2nd = new objectB();
objectA.ObjectAText = "Jane"; // both objectB1st and objectB2nd will respond to this event!

最後の行は、?のために予期しない動作を引き起こしませんでしたWeakReferenceか?

しかし、Mediatorクラスが「登録解除」メソッドを提供する場合(実際に私はそれを実装しました)、「オプション(2)WeakReference」は「オプション(1)イベントを明示的にデタッチする」と違いはありません。(メディエーター自体は依然として有用なパターンであり、WPFまたはMVVMコンポーネントレイヤーの階層に侵入できます)

4

2 に答える 2

5

あなたが何を求めているのか理解できれば、いくつかの説明が必要です。

そうしないと、イベントハンドラーのオブジェクトの1つがnullに割り当てられた場合でも、「孤立した」オブジェクトはイベントに応答します。これにより、予期しない動作が発生します。

あまり。これは予期しない動作ではありません。明示的に登録を解除しない限り、オブジェクトが呼び出されることが完全に期待されます。

弱いイベントの全体的な考え方は、オブジェクトがイベントにサブスクライブされているという理由だけでオブジェクトをメモリに保持しないためのセーフティネットです。スコープ外になったときにイベントからオブジェクトの登録を解除することとは何の関係もありません。

後で行う必要がある場合は、IDisposableパターンを使用してサブスクライバーに「using」構文を使用するか、明示的にサブスクライブを解除します。

つまり、弱いイベントは、非常に特殊な問題の解決策です。つまり、長寿命のオブジェクト(GUIや静的クラスなど)にサブスクライブされたオブジェクトのガベージコレクションを許可します。

弱いイベントは、オブジェクトがスコープから外れた瞬間でも、自動的にサブスクライブを解除することではありません。

于 2011-07-11T16:32:47.110 に答える
1

イベントサブスクライバーとパブリッシャーの両方が協力する場合、Reflectionやその他のCLRトリックを必要とせずに、.netに妥当なウィークイベントパターンを実装することができます。ファイナライザースレッドによって呼び出された場合にイベントのサブスクライブ解除メソッドが正しく機能する必要がある場合、イベントサブスクライバーが一方的にウィークイベントパターンを実装することは可能ですが、残念ながら、未知のクラスからのイベントをサブスクライブする場合、そのような期待は合理的ではありません(例:INotifyPropertyChanged)。トリックは、オブジェクトに本当に「興味がある」人がラッパーへの強い参照を保持し、イベントハンドラーやその他のものがオブジェクトの「ガッツ」への参照を保持することです。ラッパーは、内臓と、イベントのサブスクライブを解除するFinalizeメソッドを持つオブジェクトの両方への参照を保持できます。

于 2011-07-29T21:50:10.930 に答える