vsphere vcenter update for esxi enable c# multithreading concurrency exception-handling task

c# - vcenter - vsphere web client 6.5 download



Cómo manejar Task.Run Exception (5)

Tuve un problema con la captura de mi excepción de Task.Run Cambié mi código y mi problema se resolvió. Estoy dispuesto a descubrir cuál es la diferencia entre manejar las excepciones dentro de Task.Run de estas dos maneras:

En la función Fuera no puedo capturar la excepción, pero en Dentro puedo atraparla.

void Outside() { try { Task.Run(() => { int z = 0; int x = 1 / z; }); } catch (Exception exception) { MessageBox.Show("Outside : " + exception.Message); } } void Inside() { Task.Run(() => { try { int z = 0; int x = 1 / z; } catch (Exception exception) { MessageBox.Show("Inside : "+exception.Message); } }); }


Cuando se ejecuta una tarea, las excepciones que lanza se retienen y se vuelven a lanzar cuando algo espera el resultado de la tarea o la tarea se completa.

Task.Run() devuelve un objeto Task que puedes usar para hacer eso, así que:

var task = Task.Run(...) try { task.Wait(); // Rethrows any exception(s). ...

Para las versiones más nuevas de C #, puede usar await en lugar de Task.Wait ():

try { await Task.Run(...); ...

que es mucho más ordenado.

Para completar, aquí hay una aplicación de consola compilable que demuestra el uso de await :

using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static void Main() { test().Wait(); } static async Task test() { try { await Task.Run(() => throwsExceptionAfterOneSecond()); } catch (Exception e) { Console.WriteLine(e.Message); } } static void throwsExceptionAfterOneSecond() { Thread.Sleep(1000); // Sleep is for illustration only. throw new InvalidOperationException("Ooops"); } } }


En su código externo, solo verifica si iniciar una tarea no produce una excepción, no el propio cuerpo de la tarea. Se ejecuta de forma asíncrona y el código que lo inició se realiza entonces.

Puedes usar:

void Outside() { try { Task.Run(() => { int z = 0; int x = 1 / z; }).GetAwaiter().GetResult(); } catch (Exception exception) { MessageBox.Show("Outside : " + exception.Message); } }

El uso de .GetAwaiter().GetResult() espera hasta que la tarea finalice y pase la excepción lanzada tal como está y no los envuelve en AggregateException excepción AggregateException .


La idea de usar Task.Wait hará el truco pero hará que el hilo que llama (como dice el código) espere y, por lo tanto, bloquee hasta que la tarea haya finalizado, lo que efectivamente hace que el código sea síncrono en lugar de asíncrono.

En su lugar, use la opción Task.ContinueWith para lograr resultados:

Task.Run(() => { //do some work }).ContinueWith((t) => { if (t.IsFaulted) throw t.Exception; if (t.IsCompleted) //optionally do some work); });

Si la tarea debe continuar en el subproceso de la interfaz de usuario, use la opción TaskScheduler.FromCurrentSynchronizationContext () como parámetro para continuar con esto:

).ContinueWith((t) => { if (t.IsFaulted) throw t.Exception; if (t.IsCompleted) //optionally do some work); }, TaskScheduler.FromCurrentSynchronizationContext());

Este código simplemente volverá a emitir la excepción agregada del nivel de tarea. Por supuesto, también puede introducir otra forma de manejo de excepciones aquí.


Para mí, quería que mi tarea. Ejecutar continúe después de un error, dejando que la interfaz de usuario se ocupe del error ya que tiene tiempo.

Mi solución (¿extraña?) Es tener un Form.Timer en ejecución. My Task.Run tiene su cola (para cosas que no son de IU de larga duración), y mi Form.Timer tiene su cola (para cosas de UI).

Dado que este método ya estaba funcionando para mí, fue trivial agregar el manejo de errores: si la tarea.Runir recibe un error, agrega la información de error a la cola de Form.Timer, que muestra el cuadro de diálogo de error.


Solo puede esperar, y luego las excepciones aumentarán hasta el contexto de sincronización actual (vea la respuesta de Matthew Watson). O, como menciona Menno Jongerius, puede ContinueWith con el código para mantener el código asíncrono. Tenga en cuenta que puede hacerlo solo si se lanza una excepción utilizando la opción de continuación OnlyOnFaulted :

Task.Run(()=> { //.... some work.... }) // We could wait now, so we any exceptions are thrown, but that // would make the code synchronous. Instead, we continue only if // the task fails. .ContinueWith(t => { // This is always true since we ContinueWith OnlyOnFaulted, // But we add the condition anyway so resharper doesn''t bark. if (t.Exception != null) throw t.Exception; }, default , TaskContinuationOptions.OnlyOnFaulted , TaskScheduler.FromCurrentSynchronizationContext());