2016-12-03 7 views
0

私は行う予定のリストがあります。だから、サブスクリプションのリストにサブスクライバを追加します。加入者が仕事を終えた後、加入者は自身を退会しなければならない。加入者が終了した時点は不明である。加入者自身がそれを知っているだけです。その中の加入者をどのように退会させるのですか

最適なデザインパターンまたは解決策は何でしょうか。

私はオブサーバパターンを使用しました。

これは私の観察可能である:

internal class EventProvider : IObservable<double> 
{ 
    private readonly List<IObserver<double>> _observers = new List<IObserver<double>>(); 

    public IDisposable Subscribe(IObserver<double> observer) 
    { 
     // check if observer exist... 
     _observers.Add(observer); 
     return new Unsubscriber<double>(_observers, observer); 
    } 

    public void OnTimingsRecieved(double timing) // some other event fires this 
    { 
     foreach (var observer in _observers) 
     { 
      observer.OnNext(timing); 
     } 
    }   

    //... 
} 

これはオブザーバーである:(多くのオブザーバーに0が存在することができる)

internal class EventObserver : IObserver<double> 
{ 
    private IDisposable _unsubscriber; 
    private readonly IReadOnlyList<Event> _events; 

    public EventObserver(IReadOnlyList<Event> events) 
    { 
     _events = events; 
    } 

    public void Subscribe(EventProvider provider) 
    { 
     _unsubscriber = provider.Subscribe(this); 
    } 

    private int _ind; 
    public void OnNext(double timings) 
    { 
     // may move to next event or not. it depends. 
     // _ind++; may execute or not 

     if (_ind == _events.Count) OnCompleted(); // time to unsubscribe it self 
    } 

    public void OnCompleted() 
    { 
     _unsubscriber.Dispose(); 
    } 

    //... 
} 

これはいつものように実装されているUnsubscirberです。私はOnNextイベント内のオブザーバーを配置しようとすると、

internal class Unsubscriber<T> : IDisposable 
{ 
    private readonly List<IObserver<T>> _observers; 
    private readonly IObserver<T> _observer; 

    internal Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) 
    { 
     _observers = observers; 
     _observer = observer; 
    } 

    public void Dispose() 
    { 
     if (_observers.Contains(_observer)) 
      _observers.Remove(_observer); 
    } 
} 

問題が表示されます。私はforeachループの中にいたのでコレクションが変更され、リストから削除された要素が削除されました。

自分で加入者の登録を解除したい状況にどう対応しますか?より良いデザインパターンはありますか?


観測可能なオブザーバとオブザーバを使用するのではなく、さまざまなアプローチを参照してください。

このイベントがあるとします。

public event EventHandler<double> TimeDiff; 

そして、あなたはTimerDiffに接続加入者の多くのインスタンスを持っているし、自分自身を解除することができます。

public class Reciever 
{ 
    Jobs listOfJobsToDo; 

    public void TimeDiffRecieved(double diff) 
    { 
     listOfJobsToDo.DoJob(diff); 
     if(somecondition) 
      Unsubscribe(); 
    } 
} 
+1

なぜあなた自身の観測値を実装していますか?それは危険に満ちている。組み込みのRx実装を使用する必要があります。 – Enigmativity

+1

私は参照してください。私はこのオブザーバーを取り除き、あなたの時間のおかげでどのように動作するか見るためにRxを試してみるつもりです。 @Enigmativity –

答えて

0

foreachはループのために使用したコレクションの変更を処理しないので、

この場合、オブザーバーが作業しているときに、それを自分で処分することができます。その他は影響を受けません。

ここにプロバイダの修正があります。

public void OnTimingsRecieved(double timing) 
{ 
    for (int i = 0; i < _observers.Count; i++) 
    { 
     var count = _observers.Count; // save count in case it may change. 
     var observer = _observers[i]; 
     observer.OnNext(timing);  // it may only dispose it self. 
     i -= count - _observers.Count; // decrement if observer unsubscribed. 
    } 
} 
+1

このパターンを使用する場合、そのパターン(Rx(Reactive)という名前の拡張機能)のためのすぐれたソリューションを再利用することをお勧めします。 – Evk

+0

は面白そうです。それは私のために全く新しいものです。それを見ていない。ありがとうbtw。 @エヴァーク –

関連する問題