如何使用Reactive Extensions实现事件

时间:2013-03-05 18:37:45

标签: c# events system.reactive

Reactive Extensions允许您使用Observable.FromEventPattern轻松订阅活动,但是当您拥有{{{}时,我无法找到关于如何实施活动的任何内容1}}。

我的情况是这样的:我需要实现一个包含事件的接口。每当我的对象的某个值发生变化时,就会调用该事件,出于线程安全的原因,我需要在某个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函数订阅并取消订阅remove作为FooChangedHandler Observer<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相反。

2 个答案:

答案 0 :(得分:2)

你可以这样做:

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

但是,在删除时,我想也许你可能想要处理订阅...或者从ToEvent()获取Action并将其存储为成员。未经测试。

编辑:但是,您必须使用Action而不是FooChangedHandler委托。

编辑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; }
    }
}

答案 1 :(得分:0)

鉴于您已经在混合反应和更正常的代码之间的界限,您可以做一个反应较少的版本。开始只是声明一个正常的事件模式

public event FooChangedHandler FooChanged;

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

然后只需在构造函数

中将observable连接到它
m_Observable.Subscribe(foo => OnFooChanged(foo));

它不是非常Rx,但它非常简单。