c# - 如何将IEnumerable与Process.Start的输出事件处理程序一起使用?

标签 c# c++ process ienumerable

我有以下用例。我已经从Unmanned C++中创建了一个EXE。假设在控制台上打印1-100。输出捕获到下面的输出回调中

List<int> a = new List<int>();
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{ 
   a.add(Convert.ToInt(e.Data));
}

但是我想使用IEnumerable并产生e.Data的 yield 。考虑到C++ exe将拥有它自己的执行线程,因此它不会等待它提供控件。我将不得不等待执行完成。我可以捕获所有内容并准备一个列表。然后我可以一件一件地生产物品。我对您的问题是,在进程运行时,是否有任何已知的机制或方法来执行此操作?我可以在C++代码中进行哪些更改?这样我才能来回控制它?考虑此过程在C#端的一个功能下运行。

最佳答案

下一种方法可用于在外部进程运行时读取其输出:

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对象,该对象可用于循环处理流程的输出数据:
    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();
    }
    

    然后,当需要运行外部进程并在输出数据可用时立即读取其输出时,可以使用此方法:
    public static void Demo()
    {
        foreach (string line in ReadOutput("process_name.exe"))
        {
            Console.WriteLine(line);
        }
    }
    

    关于c# - 如何将IEnumerable与Process.Start的输出事件处理程序一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61771084/

    相关文章:

    c# - 反序列化来自 Json Http 响应的对象列表

    c# - vba/excel/c#将WorkSheet分割成多个文件的解决方法#

    c# - 使用 x64 时无法加载 WPF 设计器

    c++ - Visual Studio 静态链接(freeglut,glew)

    C#获取当前事件窗口的信息

    c++ - 在资源有限的不同进程之间建立共享内存?

    c# - 对 ref T 的 TypedReference 抛出 BadImageFormatException

    c++ - 参数包的模板推导和显式提供的类型

    c++ - 如何找到除数以最大化余数?

    android - 终止服务后通知仍在栏中