让我们说我有一个可以观察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();
}
答案 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;
并更改返回类型,则应该可以正常工作。