Процесс ожидания. Начните с наблюдаемого - PullRequest
0 голосов
/ 04 июля 2018

Я создал следующий код. Я предполагал, что это сработает, но это не так. Ожидание висит там бесконечно (событие Exit никогда не вызывается).

Я звоню "пинг" без аргументов, поэтому он закончится почти сразу.

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?

1 Ответ

0 голосов
/ 04 июля 2018

У вас есть состояние гонки здесь. Цитата из этой темы репозитория RX :

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, отметьте это Q / A .

...