首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Rx同步异步事件

使用Rx同步异步事件
EN

Stack Overflow用户
提问于 2010-06-02 16:54:06
回答 2查看 7K关注 0票数 7

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

代码语言:javascript
复制
class Component {

  public void BeginStart() { ... }

  public event EventHandler Started;

}

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

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

代码语言:javascript
复制
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有一个解决方案。但是怎么做呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-06-03 14:16:15

PL's answer对于你的规范来说是非常好的,但是我想你可能会得到更好的结果,不是用.First()来对抗RX,而是通过为你的组件创建一个可观察的对象来拥抱它:

代码语言:javascript
复制
    public static IObservable<Unit> AsObservable(this Component component)
    {
        return Observable.Defer(() =>
        {
            component.BeginStart();
            return Observable
                .FromEvent<EventArgs>(component, "Started")
                .Select(_ => new Unit());
        });
    }

然后,您可以将其用作阻塞:

代码语言:javascript
复制
new Component().AsObservable().First();

非阻塞:

代码语言:javascript
复制
new Component().AsObservable().Subscribe(_ => Console.WriteLine("Done"));

热门:

代码语言:javascript
复制
var pub = new Component().AsObservable().Publish();
pub.Subscribe(_ => Console.WriteLine("Sub1"));
pub.Subscribe(_ => Console.WriteLine("Sub2"));
pub.Connect();  // started just once per two subscriptions

可组合的:

代码语言:javascript
复制
new Component().AsObservable().Delay(TimeSpan.FromSeconds(1));

等等。

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

代码语言:javascript
复制
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()

票数 11
EN

Stack Overflow用户

发布于 2010-06-03 03:42:55

下面这样的代码应该可以做到:

代码语言:javascript
复制
var replay = Observable
    .FromEvent<EventArgs>(this.component, "Started")
    .Replay();
replay.Connect();
component.BeginStart();
replay.First();
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2956195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档