等待Observable的第n个OnNext()

时间:2014-10-25 12:04:59

标签: c# .net asynchronous async-await

让我们说我有一个可以观察OnNext()多次的观察。在await参数符合某个标准的那一刻,我希望OnNext。我怎么能这样做?

它几乎就像this帖子中等待进程执行的例子:

public static TaskAwaiter<int> GetAwaiter(this Process process) 
{ 
    var tcs = new TaskCompletionSource<int>(); 
    process.EnableRaisingEvents = true; 
    process.Exited += (s, e) => tcs.TrySetResult(process.ExitCode); 
    if (process.HasExited) tcs.TrySetResult(process.ExitCode); 
    return tcs.Task.GetAwaiter(); 
}

让我进入代码:我的同事编写了一个简化如下的总线实现:

public class MyBus : IObservable<MessageRecieved>
{
    public void Post(IBusMessage message)
    {
        foreach (var observer in this.observers)
        {
            observer.OnNext(new MessageRecieved(message.GetType(), MessageRecieved.MessageStage.Recieved));
        }

        message.Handle();

        foreach (var observer in this.observers)
        {
            observer.OnNext(new MessageRecieved(message.GetType(), MessageRecieved.MessageStage.Handled));
        }
    }
    // ... some more stuff
}

会发布一条消息,该消息会对消息执行某些操作,然后在总线上发布新消息。因此,总线上会发布一系列消息,然后进行处理。实际实现有点不同,并使用消息处理程序和东西,但这与问题无关。

问题是:我们需要知道它何时完成。我知道最终消息的消息类型(让我们说LastMessageType)。所以我的想法是制作一个总线工具IObservable并创建一个Observer来收集事件,并在使用LastMessageType类型捕获消息时引发事件。

然而,我见过Bart de Smet等待一系列随机事件(windows形式事件)并为此创建一个等待者。所以我想做的是:

var initialMessage = ConstructInitialMessage();
var bus = new MessageBus();
await bus.Process(initialMessage);

有人能指出我找到解决方案的方向。我已经实现了一个观察者,如果OnNext收到LastMessageType消息,就会引发一个事件,但它并不等待。像这样:

public static TaskAwaiter<int> ProcessMessage(this MyBus bus, BeginMessage message)
{
    var tcs = new TaskCompletionSource<int>();
    var observcer = new MessageObserver();
    observcer.LastMessageRecieved += () => tcs.SetResult(1);
    return tcs.Task.GetAwaiter();
}

1 个答案:

答案 0 :(得分:2)

  

所以我想做的是:

await bus.Process(initialMessage);

可以使用Rx(在您从项目中引用它之后添加using System.Reactive.Linq;)。这样做是等到observable完成(在其观察者上调用OnCompleted)。

如果由于某种原因你不能正确地修复observable,你将不得不创建一个新的observable,它在原始的observable结束时结束。为此,您可以将FirstAsync()与谓词一起使用:

await bus.Process(initialMessage).FirstAsync(
    message => message.Type == finalType 
        && message.Stage == MessageRecieved.MessageStage.Handled);
  

我已经实施了一个观察员[...],但这是不可能的。

该代码的问题是您的代码返回TaskAwaiter<int>TaskAwaiter不是等待的,Task本身就是。因此,如果您将代码更改为return tcs.Task;并更改返回类型,则应该可以正常工作。