2010-11-13 12 views
5

Di solito quando ti iscrivi alle modifiche di un valore sei anche interessato a conoscere il valore iniziale. Voglio che il mio IObservable memorizzi il valore più recente (o iniziale) e spinga quel valore alla sottoscrizione.Come posso ottenere un IObservable per inviare il valore più recente all'abbonamento

Quando si utilizzano gli eventi semplici che spesso finiscono con il codice che assomiglia

x.SomeEvent += SomeEventHandler; 
SomeEventHandler(x, EventArgs.Empty); 

Utilizzando IObservable speravo di avvolgere l'evento con qualcosa che spinge il valore iniziale. Se ho più abbonati dovrebbero ricevere il valore più recente al momento della sottoscrizione ho qualche codice che funziona bene se mi iscrivo subito dopo la creazione del IObservable ma non se l'evento prima della sottoscrizione:

class Program 
{ 
    static void Main() 
    { 
     var s = new Source { Value = 1 }; 
     var values = Observable.Return(s.Value).Concat(
      Observable.FromEvent(
       h => s.ValueChanged += h, 
       h => s.ValueChanged -= h) 
      .Select(_ => s.Value)); 
     using (values.Subscribe(Console.WriteLine)) 
     { 
      s.Value = 2; // prints 1,2 as expected 
     } 
     using (values.Subscribe(Console.WriteLine)) 
     { 
      s.Value = 3; // prints 1,3 - expected 2,3 
     } 
    } 
} 

class Source 
{ 
    private int _value; 
    public int Value 
    { 
     get { return _value; } 
     set 
     { 
      if (_value == value) 
       return; 
      _value = value; 
      if (ValueChanged != null) 
       ValueChanged(this, EventArgs.Empty); 
     } 
    } 

    public event EventHandler ValueChanged; 
} 

Come faccio a creare un IObservable che funziona come previsto?

+0

'.Selezionare (_ => s.Value)' - questo è molto strano e potrebbe rompere le cose. Non puoi cambiare l'evento 'ValueChanged' così gli argomenti dell'evento contengono il nuovo valore? – dtb

+0

Non ho scritto il codice che sto ascoltando. Se lo fossi, vorrei semplicemente esporre un IObservable invece :) –

risposta

6

La soluzione è di sottoscrivere un osservabile allo BehaviorSubject e di sottoscrivere tutti gli osservatori allo BehaviorSubject. Lo BehaviorSubject ricorderà l'ultima notifica e notificherà i nuovi osservatori al momento dell'iscrizione.

Dai un'occhiata al metodo di estensione Observable.Publish che ha un parametro initialValue. Ciò crea un IConnectableObservable che utilizza internamente uno BehaviorSubject.

var s = new Source { Value = 1 }; 

var values = Observable.FromEvent(h => s.ValueChanged += h, 
            h => s.ValueChanged -= h) 
         .Select(e => e.NewValue) 
         .Publish(s.Value); 

using (values.Connect())       // subscribes subject to event 
{ 
    using (values.Subscribe(Console.WriteLine)) // subscribes to subject 
    { 
     s.Value = 2; 
    }           // unsubscribes from subject 

    using (values.Subscribe(Console.WriteLine)) // subscribes to subject 
    { 
     s.Value = 3; 
    }           // unsubscribes from subject 

}           // unsubscribes subject from event 

(non testato)

Problemi correlati