2011-05-12 8 views
83

Uno de mi método (Method1) genera un nuevo hilo. Ese subproceso ejecuta un método (Method2) y durante la ejecución se produce una excepción. que necesito para conseguir que la información de excepción en el método de llamada (Method1)captura excepción que se lanza en hilo diferente

¿Hay alguna manera puedo coger esta excepción en Method1 que se lanza en Method2?

Respuesta

149

En .NET 4 y superior, puede utilizar la clase Task<T> en lugar de crear un nuevo hilo. Luego puede obtener excepciones usando la propiedad .Exceptions en su objeto de tarea. Hay 2 maneras de hacerlo:

  1. En un método separado: // Procesa excepción en hilo alguna tarea de

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Task<int> task = new Task<int>(Test); 
         task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted); 
         task.Start(); 
         Console.ReadLine(); 
        } 
    
        static int Test() 
        { 
         throw new Exception(); 
        } 
    
        static void ExceptionHandler(Task<int> task) 
        { 
         var exception = task.Exception; 
         Console.WriteLine(exception); 
        } 
    } 
    
  2. En el mismo método: // Usted proceso de excepción en hilo de la persona que llama de

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Task<int> task = new Task<int>(Test); 
         task.Start(); 
    
         try 
         { 
          task.Wait(); 
         } 
         catch (AggregateException ex) 
         { 
          Console.WriteLine(ex);  
         } 
    
         Console.ReadLine(); 
        } 
    
        static int Test() 
        { 
         throw new Exception(); 
        } 
    } 
    

Tenga en cuenta que la excepción que obtiene es AggregateException. Todas las excepciones reales están disponibles a través de la propiedad ex.InnerExceptions.

En .NET 3.5 puede utilizar el siguiente código:

  1. // Usted proceso de excepción en hilo del niño

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Exception exception = null; 
         Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler)); 
         thread.Start();    
    
         Console.ReadLine(); 
        } 
    
        private static void Handler(Exception exception) 
        {   
         Console.WriteLine(exception); 
        } 
    
        private static void SafeExecute(Action test, Action<Exception> handler) 
        { 
         try 
         { 
          test.Invoke(); 
         } 
         catch (Exception ex) 
         { 
          Handler(ex); 
         } 
        } 
    
        static void Test(int a, int b) 
        { 
         throw new Exception(); 
        } 
    } 
    
  2. O // procesar excepción en llamante hilo

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Exception exception = null; 
         Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception)); 
    
         thread.Start();    
    
         thread.Join(); 
    
         Console.WriteLine(exception);  
    
         Console.ReadLine(); 
        } 
    
        private static void SafeExecute(Action test, out Exception exception) 
        { 
         exception = null; 
    
         try 
         { 
          test.Invoke(); 
         } 
         catch (Exception ex) 
         { 
          exception = ex; 
         } 
        } 
    
        static void Test(int a, int b) 
        { 
         throw new Exception(); 
        } 
    } 
    
+0

Lo siento pero olvidé mencionar que estoy usando .NET 3.5. Según mi entendimiento Tarea es 4.0 cosa? –

+2

@SilverlightStudent Ok, acabo de actualizar mi respuesta para satisfacer sus requisitos. – oxilumin

+0

@oxilumin: Gracias y muy apreciado. Una pregunta de seguimiento más. Si su método Test() también toma algunos argumentos, ¿cómo modificará el método SafeExecute para esos argumentos? –

6

No se puede detectar la excepción en Method1. Sin embargo, puede detectar la excepción en Method2 y registrarla en una variable que el hilo original de ejecución puede leer y con la que puede trabajar.

+0

Gracias por su respuesta. Entonces, si Method1 es parte de Class1 y tengo una variable de tipo Exception en esa clase. Siempre que Method2 arroje una excepción, también establece esa variable de excepción en Class1. ¿Suena como un diseño justo? ¿Hay alguna forma de mejores prácticas para manejar este escenario? –

+0

Correcto, solo almacena la excepción y accede a ella más tarde. No es raro que los métodos se ejecutan en el futuro (especialmente devoluciones de llamada para cuando se haya completado Método2) a continuación, volver a lanzar la excepción de que como si ellos mismos habían provocado, pero esto realmente depende de lo que quiera. – ermau

1

El método más simple para compartir datos entre diferentes hilos es shared data de la siguiente manera (algunos es pseudo código):

class MyThread 
{ 
    public string SharedData; 

    public void Worker() 
    { 
     ...lengthy action, infinite loop, etc... 
     SharedData = "whatever"; 
     ...lengthy action... 
     return; 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     MyThread m = new MyThread(); 
     Thread WorkerThread = new Thread(m.Worker); 
     WorkerThread.Start(); 

     loop//or e.g. a Timer thread 
     { 
     f(m.SharedData); 
     } 
     return; 
    } 
} 

Puede leer acerca de este método en this nice introduction about multithreading, sin embargo, prefería leer sobre esto en el O'Reilly book C# 3.0 in a nutshell, por los hermanos Albahari (2007), que también es de acceso libre en Google Books, al igual que la versión más reciente del libro, porque también cubre la agrupación de subprocesos, primer plano contra hilos de fondo, etc. código de ejemplo. (Descargo de responsabilidad: tengo una copia desgastada de este libro)

En caso de que esté haciendo una aplicación WinForms, el uso de datos compartidos es especialmente útil, porque los controles WinForm no son seguros para subprocesos.Al usar una devolución de llamada para pasar datos del hilo de trabajo a un control WinForm, el hilo de la interfaz de usuario principal necesita un código feo con Invoke() para que ese control sea seguro para la ejecución de subprocesos. Utilizando datos compartidos en su lugar, y el System.Windows.Forms.Timer de subproceso único, con un Interval corto de, digamos, 0.2 segundos, puede enviar fácilmente información desde el subproceso de trabajo al control sin Invoke.

Cuestiones relacionadas