7

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 に解決策があることを期待しています。しかし、どのように?

4

2 に答える 2

11

PLの答えは、仕様に完全に適合している場合ですが、.First()を使用してRXと戦うのではなく、コンポーネントにオブザーバブルを作成することでRXと戦うことで、より良い結果が得られる可能性があると思いました。

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

于 2010-06-03T06:16:15.260 に答える
3

このような何かがそれを行う必要があります:

var replay = Observable
    .FromEvent<EventArgs>(this.component, "Started")
    .Replay();
replay.Connect();
component.BeginStart();
replay.First();
于 2010-06-02T19:42:55.250 に答える