7

Reactive Extensions を使用すると、 を使用してイベントを簡単にサブスクライブObservable.FromEventPatternできますが、IObservable.

私の状況は次のとおりです。イベントを含むインターフェースを実装する必要があります。そのイベントは、オブジェクトの特定の値が変更されるたびに呼び出されることになっています。スレッドの安全性の理由から、特定の でこのイベントを呼び出す必要がありますSynchronizationContext。また、登録時に現在の値を使用して各イベント ハンドラーを呼び出すことになっています。

public interface IFooWatcher
{
    event FooChangedHandler FooChanged;
}

私が望むことを行うオブザーバブルを取得することは、Rxを使用してかなり簡単です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 { /* ??? */ }
    }
}

addここで、 and関数を onとして渡されたものremoveをサブスクライブおよびサブスクライブ解除する簡単な方法を探しています。私の現在の実装は次のようになります。FooChangedHandlerObserver<Foo>m_observable

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

ただし、これらのイベントのいくつか (異なるハンドラー タイプ) を実装する必要があるため、より簡単な解決策を見つけたいと考えています。私は独自の一般的なソリューションを展開しようとしましたが、回避する必要があるいくつかの追加の問題が発生します (特に、のパラメーターを受け取るデリゲートを一般的に操作する方法T)。この方向のギャップ -FromEventPattern逆も同様です。

4

2 に答える 2

2

あなたはこれを行うことができます:

public event FooChangedHandler FooChanged
{
    add { m_observable.ToEvent().OnNext += value; }
    remove { m_observable.ToEvent().OnNext -= value; }
}

ただし、削除すると、おそらくサブスクリプションを破棄したいだけかもしれません...またはToEvent()からアクションを取得してメンバーとして保存したいかもしれません。未テスト。

編集: ただし、FooChangedHandler デリゲートの代わりに Action を使用する必要があります。

編集 2: これはテスト済みのバージョンです。ただし、これらの既存のハンドラーがたくさんあるので、FooChangedHandler を使用する必要があると思いますか?

void Main()
{
    IObservable<Foo> foos = new [] { new Foo { X = 1 }, new Foo { X = 2 } }.ToObservable();
    var watcher = new FooWatcher(SynchronizationContext.Current, new Foo { X = 12 });
    watcher.FooChanged += o => o.X.Dump();  
    foos.Subscribe(watcher.Subject.OnNext); 
}

// Define other methods and classes here

//public delegate void FooChangedHandler(Foo foo);
public interface IFooWatcher
{
    event Action<Foo> FooChanged;
}

public class Foo {
    public int X { get; set; }
}
public class FooWatcher
{

    private readonly BehaviorSubject<Foo> m_subject;
    public BehaviorSubject<Foo> Subject { get { return 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();
    }

    public event Action<Foo> FooChanged
    {
        add { m_observable.ToEvent().OnNext += value; }
        remove { m_observable.ToEvent().OnNext -= value; }
    }
}
于 2013-03-05T19:52:29.403 に答える
0

リアクティブ コードとより通常のコードの間の境界を既に混合していることを考えると、リアクティブ コードの少ないバージョンを実行できます。開始するには、通常のイベント パターンを宣言するだけです。

public event FooChangedHandler FooChanged;

protected void OnFooChanged(Foo)
{
  var temp = FooChanged;
  if (temp != null)
  {  
    temp(new FooChangedEventArgs(Foo));
  }
}

次に、オブザーバブルをコンストラクターでそれに接続するだけです

m_Observable.Subscribe(foo => OnFooChanged(foo));

それはあまり Rx ではありませんが、信じられないほど単純です。

于 2013-03-06T07:11:28.213 に答える