2009-01-02 11 views
34

Je voulais définir un gestionnaire pour toutes les exceptions inattendues que je n'aurais peut-être pas détectées dans mon code. En Program.Main() je le code suivant:Gestion du problème des exceptions non gérées

AppDomain.CurrentDomain.UnhandledException 
    += new UnhandledExceptionEventHandler(ErrorHandler.HandleException); 

Mais cela n'a pas fonctionné comme je m'y attendais. Lorsque j'ai démarré l'application en mode de débogage et que j'ai lancé une exception, le gestionnaire a été appelé, mais l'assistant d'exception de Visual Studio est apparu par la suite comme si l'exception s'était produite sans aucune manipulation. J'ai essayé Application.Exit() dans le gestionnaire, mais cela n'a pas fonctionné aussi bien.

Ce que je voudrais réaliser, c'est que l'exception est gérée avec mon gestionnaire et ensuite l'application se ferme bien. Y at-il un autre moyen de le faire ou est-ce que j'utilise le code ci-dessus dans le mauvais sens?

Répondre

27

C'est parce que vous l'exécutez via Visual Studio en mode débogage. Si vous libérez et installez votre application ailleurs, rien d'autre que votre gestionnaire d'exception global ne sera traité.

6

Notez que les exceptions non gérées sont toujours assez fatales; vous ne pouvez vraiment l'utiliser que pour la journalisation, ou peut-être une fermeture hâtive. Ni cela ni Application.ThreadException ne peut être utilisé comme puits global pour les erreurs. La meilleure approche consiste à ajouter une bonne gestion, par exemple, autour de la logique Main() entière. Notez que même ce ne peut pas attraper quelques exceptions, telles que des erreurs pendant le chargement du formulaire (qui deviennent particulièrement désagréables - vous pouvez les attraper avec un débogueur attaché, mais pas sans).

+0

bien, oui, bien sûr je sais que;) – agnieszka

+0

alors pourquoi ne pas les attraper dans Main()? –

+0

"je sais que" était une réponse à la partie "évier pour les erreurs". On m'a enseigné essayer-attraper dans la main est une chose que vous ne devriez pas faire. cependant, je dois dire honnêtement que je ne sais pas pourquoi ce serait une mauvaise approche (bien sûr si j'attrape toutes les exceptions je peux penser à l'intérieur du code) – agnieszka

31

Normalement, j'utilise quelque chose comme ça pour essayer de capturer toutes les exceptions de haut niveau inattendues.

using System; 

static class Program 
{ 
    [STAThread] 
    static void Main(string[] argv) 
    { 
    try 
    { 
     AppDomain.CurrentDomain.UnhandledException += (sender,e) 
     => FatalExceptionObject(e.ExceptionObject); 

     Application.ThreadException += (sender,e) 
     => FatalExceptionHandler.Handle(e.Exception); 

     // whatever you need/want here 

     Application.Run(new MainWindow()); 
    } 
    catch (Exception huh) 
    { 
     FatalExceptionHandler.Handle(huh); 
    } 
    } 

    static void FatalExceptionObject(object exceptionObject) { 
    var huh = exceptionObject as Exception; 
    if (huh == null) { 
     huh = new NotSupportedException(
     "Unhandled exception doesn't derive from System.Exception: " 
     + exceptionObject.ToString() 
    ); 
    } 
    FatalExceptionHandler.Handle(huh); 
    } 
} 

Peut-être que c'est quelque chose que vous trouvez utile aussi? Ce code principal achemine les trois manières d'intercepter des exceptions de niveau supérieur inattendues via un appel de méthode. Tout ce dont vous avez besoin maintenant est une classe statique FatalExceptionHandler qui inclut votre gestion des exceptions de niveau supérieur dans sa méthode Handle.

Et vraiment, tout développeur d'application sait qu'il ya vraiment que deux choses à faire là-bas:

  1. Afficher/log l'exception comme bon vous semble
  2. Assurez-vous que vous quittez/tuer le processus d'application

Si vous pensez que l'élément 2 est étrange, rappelez-vous que nous ne prenons la peine de le faire en premier lieu pour des situations vraiment exceptionnelles. Ces choses sont probablement des bugs qui nécessitent des modifications de votre application pour être traitées avec précision. Toute autre gestion d'exception - le type fonctionnel - devrait être plus bas dans votre code de programme actuel, en attrapant des types spécifiques d'exceptions là où cela est logique et en les manipulant de la manière qui convient le mieux. Tout le reste devrait bouillonner jusqu'à votre FatalExceptionHandler pour se faire connaître et arrêter le programme peut-être estropié de travailler d'un État corrompu

programmes morts ne parlent pas des mensonges ... ;-)

+0

+1 pour les programmes morts ne disent pas de mensonges ... ;-) –

+1

Comme vous pouvez le voir [Pourquoi UnhandledExceptionEventArgs.ExceptionObject est-il un objet et non une exception?] (Http://stackoverflow.com/questions/913472/why-is-unhandledexceptioneventargs-exceptionobject-an-object-and-not- an-exception) post, il * peut * être imprudent de lancer 'e.ExceptionObject' à' Exception' sans vérifier d'abord, car il ne sera pas toujours de type 'Exception' ... vous pourriez finir par créer un nouveau' Exception' ici. – Sheridan

+0

Je me demandais pourquoi c'était un objet, mais jamais réellement examiné cela. J'ai appris quelque chose de nouveau aujourd'hui. Merci! Va changer la réponse pour essayer de remédier à cela. – peSHIr

2

Peut-être ce que vous cherchez est Environment.Exit(int errorcode)

1

Ce comportement est voulu par la conception.

Mais il est une solution de rechange.

Soit vous appelez Process.GetCurrentProcess().Kill(); dans le gestionnaire, ou tout simplement ne laissez pas le gestionnaire se terminer.

Découvrez l'exemple:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

Cela ne devrait pas être un puits par défaut pour les exceptions, sûrement.

Mais cela devrait être fait pour signaler les exceptions avec élégance.

Questions connexes