161

Process.Startタイトルが示すように、私が待つことができる(別のアプリケーションまたはバッチファイルを実行できる)に相当するものはありますか?

私は小さなコンソールアプリで遊んでいます。これはasyncを使用して待つのに最適な場所のように見えましたが、このシナリオのドキュメントが見つかりません。

私が考えているのは、これらの線に沿ったものです。

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

8 に答える 8

222

Process.Start()プロセスを開始するだけで、終了するまで待機しないため、それを作成してもあまり意味がありませんasync。それでもやりたい場合は、次のようなことができますawait Task.Run(() => Process.Start(fileName))

ただし、プロセスが終了するまで非同期で待機する場合は、Exitedイベントを次のように使用できますTaskCompletionSource

static Task<int> RunProcessAsync(string fileName)
{
    var tcs = new TaskCompletionSource<int>();

    var process = new Process
    {
        StartInfo = { FileName = fileName },
        EnableRaisingEvents = true
    };

    process.Exited += (sender, args) =>
    {
        tcs.SetResult(process.ExitCode);
        process.Dispose();
    };

    process.Start();

    return tcs.Task;
}
于 2012-05-28T18:50:32.017 に答える
61

svick's answerに基づく私の見解は次のとおりです。出力のリダイレクト、終了コードの保持、わずかに優れたエラー処理 (Process開始できなかった場合でもオブジェクトを破棄する) が追加されます。

public static async Task<int> 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<int> RunProcessAsync(Process process)
{
    var tcs = new TaskCompletionSource<int>();

    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;
}
于 2015-07-18T14:38:34.883 に答える
3

ここに別のアプローチがあります。svickOhad の回答と同様の概念ですが、型で拡張メソッドを使用しProcessます。

延長方法:

public static Task RunAsync(this Process process)
{
    var tcs = new TaskCompletionSource<object>();
    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;
}

包含メソッドの使用例:

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
}
于 2018-05-29T21:48:03.510 に答える