Le estensioni reattive consentono di iscriversi facilmente ad un evento utilizzando Observable.FromEventPattern
, ma non riesco a trovare nulla su come si potrebbe implementare un evento quando si dispone di un IObservable
.come implementare un evento utilizzando reattivi estensioni
La mia situazione è questa: ho bisogno di implementare un'interfaccia che contiene un evento. Questo evento dovrebbe essere chiamato ogni volta che cambia un certo valore dell'oggetto, e per motivi di sicurezza del thread devo chiamare questo evento su un certo SynchronizationContext
. Devo anche chiamare ogni gestore di eventi con il valore corrente alla registrazione.
public interface IFooWatcher
{
event FooChangedHandler FooChanged;
}
Ottenere un osservabile che fa quello che voglio è piuttosto facile con Rx utilizzando BehaviorSubject
:
public class FooWatcher
{
private readonly BehaviorSubject<Foo> m_subject;
private readonly IObservable<Foo> m_observable;
public FooWatcher(SynchronizationContext synchronizationContext, Foo initialValue)
{
m_subject = new BehaviorSubject<Foo>(initialValue);
m_observable = m_subject
.DistinctUntilChanged()
.ObserveOn(synchronizationContext);
}
public event FooChangedHandler FooChanged
{
add { /* ??? */ }
remove { /* ??? */ }
}
}
Ora sto cercando un modo semplice per avere le add
e remove
funzioni iscriversi e cancellarsi dalla passata FooChangedHandler
come Observer<Foo>
su m_observable
. Il mio attuale implementazione è simile a questo:
add
{
lock (m_lock)
{
IDisposable disp = m_observable.Subscribe(value);
m_registeredObservers.Add(
new KeyValuePair<FooChangedHandler, IDisposable>(
value, disp));
}
}
remove
{
lock (m_lock)
{
KeyValuePair<FooChangedHandler, IDisposable> observerDisposable =
m_registeredObservers
.First(pair => object.Equals(pair.Key, value));
m_registeredObservers.Remove(observerDisposable);
observerDisposable.Value.Dispose();
}
}
Tuttavia, spero di trovare una soluzione più facile, perché ho bisogno di implementare alcuni di questi eventi (di differenti tipi di gestore). Ho provato a rollare la mia soluzione generica, ma crea alcuni problemi aggiuntivi che devono essere risolti (in particolare, come si lavora genericamente con un delegato che accetta un parametro di T
), quindi preferirei trovare una soluzione esistente per i bridge il divario in questa direzione - proprio come FromEventPattern
fa il contrario.
Grazie, non avevo visto 'ToEvent()' prima! Questo è già un grande pezzo del puzzle. La conversione tra 'Azione' e 'FooChangedHandler' è ancora un problema (sì, purtroppo siamo bloccati con questi).Problema: i delegati sono uguali se hanno lo stesso obiettivo e metodo, ma questa uguaglianza raggiunge solo un livello - se si dispone di un delegato e lo si avvolge in due istanze separate 'Azione ', saranno uguali, ma se si avvolgono entrambi quelli 'Azione ' istanze in un'altra 'Azione ' ognuna, * quelle * non * non * saranno uguali. Tuttavia, penso di aver già visto una soluzione a questo ... –
Medo42
Ah sì, ecco: http://stackoverflow.com/a/9290684/575615 Lo proverò domani, grazie ancora! – Medo42
Tutto funziona come previsto ora. L'utilizzo di una soluzione come quella sopra indicata per la conversione dei delegati in "Azione" mi ha permesso di scrivere una soluzione generica breve e dolce che funziona internamente con 'ToEvent()'. Non c'è molto per quella classe, ma volevo raggruppare 'Subject' e' IEventSource' in un unico oggetto. –
Medo42