[英]How to use IEnumerable with Process.Start's output event handler?
我有以下用例。 我從 Unmanned C++ 創建了一個 EXE。 假設在控制台上打印 1 - 100。 output 被捕獲到下面的 output 回調中
List<int> a = new List<int>();
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
a.add(Convert.ToInt(e.Data));
}
但是我想使用 IEnumerable 並產生 e.Data 的返回。 考慮到 C++ exe 將有它自己的執行線程,它不會等待它提供控制。 我將不得不等待它的執行完成。 我可以捕獲所有內容並准備一份清單。 然后我可以一件一件地產出物品。 我的問題是在進程運行時是否有任何已知的機制或方法可以做到這一點? 我可以在我的 C++ 代碼中更改什么? 這樣它就可以讓我來回控制它? 考慮此過程在 C# 側的一個 function 下運行。
下一個方法可以用來在運行時讀取外部進程的output:
var proc = new Process
{
StartInfo =
{
FileName = "process_name.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
},
// Set this property to true to enable external
// process raise notification that is has exited.
EnableRaisingEvents = true
};
// BlockingCollection is a thread safe producer-consumer
// collection. We use it to collect the output of the
// external process and to process it while the process
// is running.
var lines = new BlockingCollection<string>();
proc.OutputDataReceived += (s, e) =>
{
// Here we collect the output of the external process.
if (!string.IsNullOrEmpty(e.Data))
lines.Add(e.Data);
};
// This event is raised when external process exits.
proc.Exited += (s, e) =>
{
// Here we notify our BlockingCollection that no more
// data to process is available.
lines.CompleteAdding();
};
proc.Start();
proc.BeginOutputReadLine();
// Here we start to process the output of the external process
// without waiting for it to exit.
// This loop iterates over the items produced by the
// BlockingCollection until method CompleteAdding is called.
// This loop is being executed while external process is
// running and finishes when the process exits.
foreach (string line in lines.GetConsumingEnumerable())
{
Console.WriteLine(line);
}
// Here we do not need to call proc.WaitForExit(), because
// loop over lines collection finishes when proc exits.
以下是學習理解此代碼示例的鏈接:
Process.EnableRaisingEvents
Process.Exited
BlockingCollection
BlockingCollection.CompleteAdding
BlockingCollection.GetConsumingEnumerable
為方便起見,我們可以創建一個啟動外部進程並立即返回IEnumerable
object 的方法,該方法可用於循環遍歷進程的 output 數據:
private static IEnumerable<string> ReadOutput(string procFileName)
{
var proc = new Process
{
StartInfo =
{
FileName = procFileName,
UseShellExecute = false,
RedirectStandardOutput = true,
},
EnableRaisingEvents = true
};
var lines = new BlockingCollection<string>();
proc.OutputDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
lines.Add(e.Data);
};
proc.Exited += (s, e) =>
{
lines.CompleteAdding();
};
proc.Start();
proc.BeginOutputReadLine();
return lines.GetConsumingEnumerable();
}
然后我們可以在需要運行外部進程並在 output 數據可用時立即讀取其 output 時使用此方法:
public static void Demo()
{
foreach (string line in ReadOutput("process_name.exe"))
{
Console.WriteLine(line);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.