2016-12-03 8 views
0

У меня есть список событий. Поэтому я добавляю подписчика в список подписки. после того, как абонент завершит свою работу, он должен отказаться от подписки. он неизвестен, когда абонент заканчивает работу. об этом знает сам абонент.Как отписаться от подписчика внутри себя

Что было бы лучшим шаблоном дизайна или решением для него.

Я использовал Наблюдательный шаблон.

Это мой Observable:

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, который реализуется как обычно ,

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); 
    } 
} 

Проблема возникает, когда я пытаюсь избавиться наблюдателя внутри OnNext события. коллекция была изменена, потому что я был внутри цикла foreach, и я удалил i.e удаленный элемент из списка.

Как вы справитесь с ситуацией, когда вы хотите отписаться от подписчика внутри себя? есть ли лучшие шаблоны дизайна?

Я ценю, что вижу разные подходы, а не наблюдая и наблюдаю.

Предположим, у вас есть это событие.

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

выглядит интересным. это совершенно новая вещь для меня. плохо смотри на это. спасибо, кстати. @Evk –