C# 使用RX同步多个事件

C# 使用RX同步多个事件,c#,system.reactive,C#,System.reactive,假设我在一个列表中有三种产品。为了启用某个特定的操作,这三个操作都需要具有特定的类型。为了找出产品的类型,我需要打一个服务电话并等待响应 我想做的是等待所有三个响应,可能会有一个超时,以防出现问题,当收集到所有信息时,决定是否启用可能的操作 我曾经通过使用一些计数器或重置事件来跟踪已完成的事件来解决这个问题,但我想看看是否可以使用Rx以更干净的方式完成 由于我还不太熟悉Rx,我正在寻找一些提示/指针。我知道我可以用 Observable.FromEventPattern 为了我等待的事件。我订

假设我在一个列表中有三种产品。为了启用某个特定的操作,这三个操作都需要具有特定的类型。为了找出产品的类型,我需要打一个服务电话并等待响应

我想做的是等待所有三个响应,可能会有一个超时,以防出现问题,当收集到所有信息时,决定是否启用可能的操作

我曾经通过使用一些计数器或重置事件来跟踪已完成的事件来解决这个问题,但我想看看是否可以使用Rx以更干净的方式完成

由于我还不太熟悉Rx,我正在寻找一些提示/指针。我知道我可以用

Observable.FromEventPattern

为了我等待的事件。我订阅并等待响应并处理它。我只是不清楚如何组合多个事件。

您正在寻找的组合器是CombineTest

假设你有这样一门课:

public class Foo
{
    public delegate void FooEventHandler(object sender, EventArgs args);

    public event FooEventHandler FirstEvent = delegate {};    
    public event FooEventHandler SecondEvent = delegate {};    
    public event FooEventHandler ThirdEvent = delegate {};    

    public void DoIt()
    {
        FireOne();
        FireTwo();
        FireThree();
    }

    public void FireOne()
    {
        Console.WriteLine("Firing event 1...");
        Thread.Sleep(1000);
        FirstEvent(this, new EventArgs());
    }
    public void FireTwo()
    {
        Console.WriteLine("Firing event 2...");
        Thread.Sleep(1000);
        SecondEvent(this, new EventArgs());
    }
    public void FireThree()
    {
        Console.WriteLine("Firing event 3...");
        Thread.Sleep(1000);
        ThirdEvent(this, new EventArgs());
    }
}
首先,您希望将这些事件转换为可观察事件:

现在,当所有这些都触发选择器时,您将需要唯一的一次触发,这是CombineTest:

为了测试它:

using(allDone.Subscribe(_ => Console.WriteLine("Boop! You sunk my battleship!")))
{
    foo.DoIt();
}    
备用测试线束:

var foo = new Foo();
var firstWatcher = Observable.FromEventPattern(foo, "FirstEvent");
var secondWatcher = Observable.FromEventPattern(foo, "SecondEvent");
var thirdWatcher = Observable.FromEventPattern(foo, "ThirdEvent");

var allDone = Observable.CombineLatest(firstWatcher, secondWatcher, thirdWatcher);

// keep a handle on the subscription            
IDisposable subscription = null;

// to prevent premature exiting...
var blocker = new ManualResetEvent(false);

// explicit subscribe
subscription = allDone.Subscribe(
    whoCares => 
    {
        Console.WriteLine("BOOM! We're done!");
        // always clean up after yourself
        if(subscription != null)
        {
            subscription.Dispose();
        }
        // it's ok, we can quit now
        blocker.Set();
    });

foo.DoIt();

// Wait until it's clear to go ahead...
blocker.WaitOne();

你要找的组合器是最适合组合的

假设你有这样一门课:

public class Foo
{
    public delegate void FooEventHandler(object sender, EventArgs args);

    public event FooEventHandler FirstEvent = delegate {};    
    public event FooEventHandler SecondEvent = delegate {};    
    public event FooEventHandler ThirdEvent = delegate {};    

    public void DoIt()
    {
        FireOne();
        FireTwo();
        FireThree();
    }

    public void FireOne()
    {
        Console.WriteLine("Firing event 1...");
        Thread.Sleep(1000);
        FirstEvent(this, new EventArgs());
    }
    public void FireTwo()
    {
        Console.WriteLine("Firing event 2...");
        Thread.Sleep(1000);
        SecondEvent(this, new EventArgs());
    }
    public void FireThree()
    {
        Console.WriteLine("Firing event 3...");
        Thread.Sleep(1000);
        ThirdEvent(this, new EventArgs());
    }
}
首先,您希望将这些事件转换为可观察事件:

现在,当所有这些都触发选择器时,您将需要唯一的一次触发,这是CombineTest:

为了测试它:

using(allDone.Subscribe(_ => Console.WriteLine("Boop! You sunk my battleship!")))
{
    foo.DoIt();
}    
备用测试线束:

var foo = new Foo();
var firstWatcher = Observable.FromEventPattern(foo, "FirstEvent");
var secondWatcher = Observable.FromEventPattern(foo, "SecondEvent");
var thirdWatcher = Observable.FromEventPattern(foo, "ThirdEvent");

var allDone = Observable.CombineLatest(firstWatcher, secondWatcher, thirdWatcher);

// keep a handle on the subscription            
IDisposable subscription = null;

// to prevent premature exiting...
var blocker = new ManualResetEvent(false);

// explicit subscribe
subscription = allDone.Subscribe(
    whoCares => 
    {
        Console.WriteLine("BOOM! We're done!");
        // always clean up after yourself
        if(subscription != null)
        {
            subscription.Dispose();
        }
        // it's ok, we can quit now
        blocker.Set();
    });

foo.DoIt();

// Wait until it's clear to go ahead...
blocker.WaitOne();

谢谢大家的帮助。非常有用。如果事件是异步的,例如,如果我们调用FireOne | Two | Three,并且这些事件在进行一些异步调用后立即返回,而不触发事件,情况如何?我尝试了我的活动,它看起来像是使用全部完成。。。将在事件完成之前退出,因此除非我做错了什么,否则不会调用allDone处理程序。例如,如果public void FireOne包含int msDelay=8000,您是否有如何使当前示例工作的示例;Task Task=Task.Factory.StartNew=>Thread.SleepmsDelay.ContinueWithTask starter=>{Console.WriteLineEVENT 1;FirstEventthis,new EventArgs;},TaskContinuationOptions.LongRunning;实际发生的是,在我这个蹩脚的小示例中,程序在事件触发之前结束——更重要的是,在allDone.Subscribe中创建的订阅正在被释放。将Console.ReadLine、Thread.Sleep10000或任何您想要的东西放在该文件的右大括号之前。或者,存储它创建的IDisposable并自行处理。感谢您的帮助。非常有用。如果事件是异步的,例如,如果我们调用FireOne | Two | Three,并且这些事件在进行一些异步调用后立即返回,而不触发事件,情况如何?我尝试了我的活动,它看起来像是使用全部完成。。。将在事件完成之前退出,因此除非我做错了什么,否则不会调用allDone处理程序。例如,如果public void FireOne包含int msDelay=8000,您是否有如何使当前示例工作的示例;Task Task=Task.Factory.StartNew=>Thread.SleepmsDelay.ContinueWithTask starter=>{Console.WriteLineEVENT 1;FirstEventthis,new EventArgs;},TaskContinuationOptions.LongRunning;实际发生的是,在我这个蹩脚的小示例中,程序在事件触发之前结束——更重要的是,在allDone.Subscribe中创建的订阅正在被释放。将Console.ReadLine、Thread.Sleep10000或任何您想要的东西放在该文件的右括号之前。或者,存储它创建的IDisposable并自行处理