繁体   English   中英

使用Rx同步异步事件

[英]Using Rx to synchronize asynchronous events

我想充分利用Reactive Extensions for .NET(Rx) ,并希望得到一些关于做一些基本任务的意见。 为了说明我正在尝试做什么,我有一个人为的例子,我有一个带有异步事件的外部组件:

class Component {

  public void BeginStart() { ... }

  public event EventHandler Started;

}

通过调用BeginStart()启动该组件。 此方法立即返回,稍后,当组件完成启动时,将触发Started事件。

我想通过包装组件来创建一个同步启动方法,并等待Started事件被触发。 这是我到目前为止所提出的:

class ComponentWrapper {

  readonly Component component = new Component();

  void StartComponent() {
    var componentStarted =
      Observable.FromEvent<EventArgs>(this.component, "Started");
    using (var startedEvent = new ManualResetEvent(false))
      using (componentStarted.Take(1).Subscribe(e => { startedEvent.Set(); })) {
        this.componenet.BeginStart();
        startedEvent.WaitOne();
      }
  }

}

我想摆脱ManualResetEvent ,我希望Rx有一个解决方案。 但是怎么样?

PL的答案如果完全符合你的规范,但我认为你可以通过不与RX对战来获得更好的结果.First()但是通过为你的组件创建一个observable来接受它:

    public static IObservable<Unit> AsObservable(this Component component)
    {
        return Observable.Defer(() =>
        {
            component.BeginStart();
            return Observable
                .FromEvent<EventArgs>(component, "Started")
                .Select(_ => new Unit());
        });
    }

然后你可以用它作为阻塞:

new Component().AsObservable().First();

非阻塞:

new Component().AsObservable().Subscribe(_ => Console.WriteLine("Done"));

热:

var pub = new Component().AsObservable().Publish();
pub.Subscribe(_ => Console.WriteLine("Sub1"));
pub.Subscribe(_ => Console.WriteLine("Sub2"));
pub.Connect();  // started just once per two subscriptions

可组合:

new Component().AsObservable().Delay(TimeSpan.FromSeconds(1));

等等...

编辑:对于您必须等待并收集信息的多个事件的情况,可以使用以下变体:

public static IObservable<EventArgs> AsObservable(this Component component)
{
    return Observable.Defer(() =>
    {
        component.BeginStart();
        return 
            Observable.FromEvent<EventArgs>(component, "Started1").Take(1)
                .Merge(
            Observable.FromEvent<EventArgs>(component, "Started2").Take(1))
                .Select(evt => evt.EventArgs);
    });
}

有了这个,如果你想阻止直到完成,你可以使用.AsObservable.Last()

这样的事情应该这样做:

var replay = Observable
    .FromEvent<EventArgs>(this.component, "Started")
    .Replay();
replay.Connect();
component.BeginStart();
replay.First();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM