はじめに
非同期のコードはいくつかパターンがありますが、なるべく一つにしたいため、async/awaitに統一できないか検討するなかで、Process.StartとExitedイベントのパターンをasync/awaitで記述する方法を見つけたのでメモしておきます。
参考
下記、stackoverflowを参考にしました。ほぼリンク先の通りです。
https://stackoverflow.com/questions/10788982/is-there-any-async-equivalent-of-process-start
コード
ある2つのファイル(sourceFileName, destinationFileName)に対してFCコマンドを実行し、結果を取得するサンプルです。
private async Task StartCommandAsync(string sourceFileName, string destinationFileName) {
//Processを非同期に実行
using (Process process = this.CreateFCProcess(sourceFileName, destinationFileName)) {
await this.StartCommandAsync(process);
}
}
private Task StartCommandAsync(Process process) {
var tcs = new TaskCompletionSource<bool>();
bool started = false;
process.Exited += (sender, args) => {
tcs.SetResult(true);
};
process.OutputDataReceived += (sender, args) => {
if (!string.IsNullOrEmpty(args.Data)) {
this.m_FCResult += $"{args.Data}\n";
}
};
process.ErrorDataReceived += (sender, args) => {
if (!string.IsNullOrEmpty(args.Data)) {
this.m_FCResult += $"Error : {args.Data}\n";
}
};
//プロセスからの情報を受け取る変数の初期化
this.m_FCResult = "";
//プロセスの開始
started = process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return tcs.Task;
}
private Process CreateFCProcess(string sourceFileName,string destinationFileName) {
ProcessStartInfo info = new ProcessStartInfo() {
FileName = "FC",
Arguments = $"\"{sourceFileName}\" \"{destinationFileName}\"",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Process process = new Process() {
StartInfo = info,
EnableRaisingEvents = true,
};
return process;
}
おわりに
最終的には、Exitedイベント内で、FCの結果をProcess.ExitCodeで取得したりしていますが、サンプルには含めませんでした。
AsParallelと組み合わせて並列化してみようかとチャレンジしてみましたが、どうも正しくExitCodeが取れず、断念。
結局、この例はあまり非同期実行する意味が無いサンプルになっている状態です。
※実際は、もっと時間のかかる自作VBScriptを非同期で実行するために調べていたのですが、サンプルとしてわかりにくくなるかなと思い、Window標準コマンドを実行するサンプルにしました。