Lo siguiente asume .NET 4.0 y el uso del TaskScheduler por defecto.
Ante todo aviso de que las excepciones son criados dentro los delegados que pasas, por lo que se crían en un hilo diferente, no en el que (lógicamente) está haciendo su catch
. De alguna forma, la excepción debe propagarse desde el hilo que ejecuta su delegado/código lambda al que inició el hilo/tarea.
Tenga en cuenta que para Task
, creo que la biblioteca también puede optar por no ejecutarlo en su propio hilo, sino más bien en el subproceso de llamada (pero no estoy seguro de si era cierto que sólo para Parallel.ForEach
, etc., y no para un objeto "desnudo" Task
).
Para que dos suceda, dos cosas deben cumplirse:
- hilo El llamado es todavía activo. De lo contrario, no queda nada que realmente pueda realizar la captura.
- La excepción que se produjo en el subproceso/tarea debe de alguna manera conservarse y volverse a subir para que pueda atraparla.
Dicho esto, ambos ejemplos no esperan a que el subproceso/tarea finalice. En el primer ejemplo, falta un task.Wait()
(o similar) y en el segundo, un thread.Join()
. Dependiendo del comportamiento de temporización de los códigos de prueba, esto puede significar que nunca podrá observar la excepción del subproceso/tarea (elemento 1 anterior).
Incluso si se agrega una llamada a esto es lo que sucede para mí (de nuevo .NET 4.0):
Tarea ejemplo: la llamada a task.Wait()
realidad vuelve a subir la excepción dada originalmente no controlada en la tarea de delegar (esto es lo que el TPL hará por ti internamente), lo envuelve dentro de un System.AggregateException
, que podrías/verías si usas algo más preciso que un "catch-all" plano.
Tema ejemplo: la excepción planteada por el delegado sigue siendo controlada y sus salidas de aplicación (a menos que haga algo para hacer frente a unhandled exceptions differently)
En otras palabras, me tendría los ejemplos de la siguiente manera:
// Thread example
var thread = new Thread(() => { throw null; });
thread.Start();
thread.Join();
// Should never reach here, depending on timing sometimes not even
// until the Join() call. The process terminates as soon as the other
// thread runs the "throw null" code - which can logically happen somewhere
// after the "start" of the "Start()" call.
// Task example
try
{
var task = new Task(() => { throw null; });
task.Start();
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("Exception: " + ex);
}
Cambió el número de versión de 5.0 a 4.5. Espero que no te importe. (Será C# 5, pero .NET 4.5.) –
@Jon en absoluto; de hecho, gracias por corregirme. –