【问题标题】:How to "await" "process.OutputDataReceived" event in C#?如何在 C# 中“等待”“process.OutputDataReceived”事件?
【发布时间】:2012-02-20 02:46:45
【问题描述】:

目前我有这个代码:

TaskCompletionSource<String> tcs = new TaskCompletionSource<String>();

// ...

process.OutputDataReceived += (sender, e) =>
{
    if (e.Data == null)
    {
        outputWaitHandle.Set();
    }
    else
    {
        tcs.SetResult(e.Data.ToString());
    }
};

// ...

return tcs.Task;

那么这个函数的用户的工作方式是:

private async void Foo_Click(object sender, RoutedEventArgs e)
{
    String output = await ExecuteCommand();
}

现在的问题是我收到了这个错误:

“System.InvalidOperationException”类型的第一次机会异常 发生在 mscorlib.dll 类型的未处理异常 在 mscorlib.dll 中发生“System.InvalidOperationException”

附加信息:已尝试将任务转换为 完成时的最终状态

当我使用tcs.SetResult()时抛出这个问题。

【问题讨论】:

  • 能否提供任务完成源的封装方法的签名>

标签: c# asynchronous async-await


【解决方案1】:

您正在包装基于事件的异步模式 (EAP)。

试试这篇 MSDN 文章:TPL and Traditional .NET Asynchronous Programming

一旦你有了Task&lt;T&gt;,你就可以await它。

【讨论】:

  • MSDN 上有一个例子:How to: Wrap EAP Patterns in a Task。只需在您的 async 方法中返回 Task&lt;T&gt;await 即可。
  • 我有Task&lt;String&gt; task;,然后我返回return task;,它告诉我Error 3 Cannot implicitly convert type 'System.Threading.Tasks.Task&lt;string&gt;' to 'string',尽管函数的返回类型是Task&lt;String&gt;
【解决方案2】:

OutputDataReceived 事件发生在写入 stdout 的每一行上(然后在完成后最后一次使用 Data == null,正如您似乎已经知道的那样),所以您收到该异常是因为您正在尝试这样做多次设置结果。

假设您想为代码保持相同的结构,您的 else 子句应该从 tcs.SetResult(e.Data.ToString());将 e.Data 中的行存储在 StringBuffer 或 List 或其他任何东西中(它不包括换行符,所以如果你想保留它,你需要自己添加回来)。

然后你的'if'子句将执行 tcs.SetResult(stringBuffer.ToString());在执行 outputWaitHandle.Set() 之前(或者您决定存储这些行)

确保你有 RedirectStandardOutput = true 和 RedirectStandardError = false 因为否则如果进程写入足够的标准错误并且你请求它被重定向但没有读取它,它可能会阻塞。有关详细信息,请在文档@http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror.aspx 中搜索“死锁”

【讨论】:

    猜你喜欢
    • 2020-08-31
    • 2018-12-27
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多