[英]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.