我创建了以下代码。我以为它可以用,但不能用。等待无限期地挂在那里(永远不会调用退出事件)。
我不带任何参数调用“ ping”,所以它几乎立即结束。
using System;
using System.Diagnostics;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static async Task Main(string[] args)
{
var process = new Process
{
StartInfo =
{
FileName = "ping",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
},
EnableRaisingEvents = true
};
var obs = Observable.FromEventPattern(handler => process.Exited += handler, handler => process.Exited -= handler);
var started = process.Start();
if (!started)
{
throw new InvalidOperationException("Could not start process: " + process);
}
await obs.FirstAsync();
}
}
}
能否请您告诉我如何使用IObservable使其工作?
答案 0 :(得分:1)
您在这里有比赛条件。来自this RX repro thread的引用:
FirstAsync返回一个可观察到的寒冷。直到您订阅 还是等待您会收到消息。
与TaskCompletionSource
(在此使用更合适,IMO)不同,FirstAsync
返回的可观察对象并不会“缓存”之前发生的事件。 >您通过等待订阅来激活它。因此,process.Exited
事件在await obs.FirstAsync()
之前被触发,因此.NET启动代码阻止了Main
返回的任务。
以下内容将按预期工作(您需要添加using System.Reactive.Threading.Tasks
):
var task = obs.FirstAsync().ToTask();
var started = process.Start();
if (!started)
{
throw new InvalidOperationException("Could not start process: " + process);
}
await task;
在此之前,我们通过将可观察的订阅转换为Task
来激活它。
如果对Observable.FromEventPattern
之类的东西感兴趣但对TaskCompletionSource
感兴趣,请选中this Q/A。