¿Cómo "esperar" el evento "Process.outputDatarCeived" en C#?
-
27-10-2019 - |
Pregunta
Actualmente tengo este código:
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;
Entonces el usuario de esta función funciona como:
private async void Foo_Click(object sender, RoutedEventArgs e)
{
String output = await ExecuteCommand();
}
Ahora el problema es que recibo este error:
Una excepción de primera oportunidad del tipo 'System.InvalidOperationException' ocurrió en mscorlib.dll una excepción no controlada del tipo 'System.InvalidOperationException' ocurrió en mscorlib.dll
Información adicional: se intentó hacer la transición de una tarea a un estado final cuando ya había completado
Este problema se arroja cuando uso tcs.SetResult()
.
Solución
El evento OutputDatarCeived ocurre en cada línea escrito en Stdout (y luego una última vez con Data == NULL cuando está hecho, como parece que ya sabe), por lo que está obteniendo esa excepción porque está tratando de hacer SetResult varias veces .
Suponiendo que desea mantener la misma estructura para el código, su cláusula más debe cambiar de tcs.setResult (e.data.ToString ()); Para almacenar la línea en E.Data en una lista o lista o lo que sea (no incluye la nueva línea, por lo que si desea preservarla, deberá agregarla usted mismo).
Entonces su cláusula 'If' hará el tcs.setResult (stringBuffer.ToString ()); (o sin embargo, decidió almacenar las líneas) antes de hacer el outputwaithandle.set ()
Asegúrese de tener redirectionStandoDoutput = True y redirectAntandarderRor = falso, ya que de lo contrario el proceso puede bloquear si escribe suficiente stderr y solicitó que se redirle pero no lo haya leído. Para obtener detalles sobre eso, busque 'Deadlock' en el documento @ http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror.aspx
Otros consejos
Estás envolviendo el patrón asíncrono basado en eventos (EAP).
Prueba este artículo de MSDN: TPL y programación asincrónica .NET tradicional
Una vez que tengas un Task<T>
, puedes await
eso.