web-dev-qa-db-fra.com

Traitement du problème des exceptions non gérées

Je voulais définir un gestionnaire pour toutes les exceptions inattendues que je n'aurais peut-être pas détectées dans mon code. Dans Program.Main() j'ai utilisé le code suivant:

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

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

Ce que j'aimerais réaliser, c'est que l'exception soit gérée avec mon gestionnaire, puis l'application se ferme correctement. Existe-t-il un autre moyen de le faire ou est-ce que j'utilise le code ci-dessus de manière incorrecte?

36
agnieszka

C'est parce que vous l'exécutez dans Visual Studio en mode débogage. Si vous publiez et installez votre application ailleurs, seul votre gestionnaire d'exception global sera traité.

29
Peter Lindholm

J'utilise normalement quelque chose comme ceci pour essayer d'attraper toutes les exceptions inattendues de niveau supérieur.

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 façons d'attraper les exceptions de niveau supérieur inattendues par le biais d'un appel de méthode. Vous n'avez plus besoin que d'une classe statique FatalExceptionHandler qui inclut la gestion des exceptions de niveau supérieur dans sa méthode Handle.

Et vraiment, tout développeur d’application sait qu’il n’ya vraiment que deux choses à faire:

  1. Afficher/consigner l'exception comme bon vous semble
  2. Assurez-vous de quitter/tuer le processus d'application

Si vous pensez que le point deux est étrange, rappelez-vous que nous ne prenons la peine de le faire en premier lieu que dans des situations vraiment exceptionnelles. Ce sont probablement des bogues qui nécessitent des modifications dans votre application pour pouvoir être résolus avec précision. Toute autre gestion des exceptions - le type fonctionnel - doit figurer plus bas dans votre code de programme réel, en capturant des types spécifiques d'exceptions lorsque cela est utile et de les gérer de manière appropriée. Tout le reste devrait apparaître dans votre FatalExceptionHandler pour se faire connaître et empêcher le programme potentiellement handicapé de fonctionner à partir d'un état corrompu

Programmes morts ne mentent pas ... ;-)

33
peSHIr

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 ceci ni Application.ThreadException ne peuvent être utilisés en tant que récepteur global pour les erreurs.

La meilleure approche consiste à ajouter un traitement approprié, par exemple autour de toute votre logique Main(). Notez que même ceci ne peut pas capturer quelques exceptions, telles que des erreurs lors du chargement du formulaire (qui sont particulièrement pénibles - vous pouvez les récupérer avec un débogueur attaché, mais pas sans).

8
Marc Gravell

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

2
Yariv

Ce comportement est voulu.

Mais il est une solution de contournement.

Soit vous appelez Process.GetCurrentProcess().Kill(); dans le gestionnaire, ou simplement vous 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 sûrement pas être un puits par défaut pour les exceptions.

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

0
bohdan_trotsenko