Existe algum equivalente asynchronous do Process.Start?

Como o título sugere, existe um equivalente a Process.Start (permite que você execute outro aplicativo ou arquivo de lote) que eu possa aguardar?

Eu estou jogando com um pequeno aplicativo de console e este parecia ser o lugar perfeito para usar async e aguardar, mas não consigo encontrar qualquer documentação para este cenário.

O que eu estou pensando é algo ao longo destas linhas:

 void async RunCommand() { var result = await Process.RunAsync("command to run"); } 

Process.Start() apenas inicia o processo, ele não espera até que seja finalizado, portanto não faz muito sentido torná-lo async . Se você ainda quiser fazer isso, você pode fazer algo como await Task.Run(() => Process.Start(fileName)) .

Mas, se você quiser esperar de forma assíncrona pelo processo, você pode usar o evento Exited junto com TaskCompletionSource :

 static Task RunProcessAsync(string fileName) { var tcs = new TaskCompletionSource(); var process = new Process { StartInfo = { FileName = fileName }, EnableRaisingEvents = true }; process.Exited += (sender, args) => { tcs.SetResult(process.ExitCode); process.Dispose(); }; process.Start(); return tcs.Task; } 

Aqui está a minha opinião, com base na resposta de svick . Ele adiciona o redirecionamento de saída, a retenção do código de saída e um tratamento de erros um pouco melhor (descartando o object Process mesmo que não possa ser iniciado):

 public static async Task RunProcessAsync(string fileName, string args) { using (var process = new Process { StartInfo = { FileName = fileName, Arguments = args, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }, EnableRaisingEvents = true }) { return await RunProcessAsync(process).ConfigureAwait(false); } } private static Task RunProcessAsync(Process process) { var tcs = new TaskCompletionSource(); process.Exited += (s, ea) => tcs.SetResult(process.ExitCode); process.OutputDataReceived += (s, ea) => Console.WriteLine(ea.Data); process.ErrorDataReceived += (s, ea) => Console.WriteLine("ERR: " + ea.Data); bool started = process.Start(); if (!started) { //you may allow for the process to be re-used (started = false) //but I'm not sure about the guarantees of the Exited event in such a case throw new InvalidOperationException("Could not start process: " + process); } process.BeginOutputReadLine(); process.BeginErrorReadLine(); return tcs.Task; } 

Aqui está outra abordagem. Conceito semelhante às respostas de svick e Ohad, mas usando um método de extensão no tipo de Process .

Método de extensão:

 public static Task RunAsync(this Process process) { var tcs = new TaskCompletionSource(); process.EnableRaisingEvents = true; process.Exited += (s, e) => tcs.TrySetResult(null); // not sure on best way to handle false being returned if (!process.Start()) tcs.SetException(new Exception("Failed to start process.")); return tcs.Task; } 

Exemplo de caso de uso em um método de contenção:

 public async Task ExecuteAsync(string executablePath) { using (var process = new Process()) { // configure process process.StartInfo.FileName = executablePath; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; // run process asynchronously await process.RunAsync(); // do stuff with results Console.WriteLine($"Process finished running at {process.ExitTime} with exit code {process.ExitCode}"); };// dispose process }