36 votes

Lancer plusieurs exceptions en .Net / C #

Dans une application, je travail sur toute la logique métier erreur provoque la levée d'une exception, et le code appelant gère l'exception. Ce modèle est utilisé tout au long de l'application et fonctionne bien.

J'ai une situation où je vais tenter d'exécuter un certain nombre de tâches à partir de l'intérieur de la couche de gestion. La condition pour cela est que l'échec d'une tâche ne doit pas causer la fin du processus. D'autres tâches devraient toujours être en mesure d'exécuter. En d'autres termes, ce n'est pas une opération atomique. Le problème que j'ai c'est qu'à la fin de l'opération, je tiens à avertir le code appelant qu'une ou des exceptions ne se produire par la levée d'une exception. Considérez les points suivants pseudo-extrait de code:

function DoTasks(MyTask[] taskList)
{
  foreach(MyTask task in taskList)
  {
    try
    {
       DoTask(task);
    }
    catch(Exception ex)
    {
        log.add(ex);
    }
  }

  //I want to throw something here if any exception occurred
}

Que dois-je les jeter? J'ai rencontré cette situation avant dans ma carrière. Dans le passé, j'ai gardé une liste de toutes les exceptions, puis jeté une exception qui contient tous les pêchés des exceptions. Cela ne semble pas être la plus élégante de l'approche. Il est important de préserver autant de détails que possible à partir de chaque exception de présenter le code appelant.

Pensées?


Edit: La solution doit être écrite .Net 3.5. Je ne peut pas utiliser de bêta bibliothèques, ou de l'AggregateException dans .Net 4.0, comme mentionné par Bradley Grainger (ci-dessous) serait une belle solution pour la collecte des exceptions à jeter.

39voto

Bradley Grainger Points 12126

La Task Parallel Library extensions pour .NET (qui va devenir une partie de .NET 4.0) suivre le modèle suggéré dans d'autres réponses: la collecte de toutes les exceptions qui ont été jetés dans une AggregateException classe.

Toujours en le jetant du même type (si il y a une exception à l'enfant de travailler, ou de beaucoup), le code d'appel qui gère l'exception est plus facile à écrire.

Dans l' .NET 4.0 CTP, AggregateException a un constructeur public (qui prend IEnumerable<Exception>); il peut être un bon choix pour votre application.

Si vous ciblez .NET 3.5, envisager le clonage de l'parties de l' System.Threading.AggregateException classe que vous avez besoin dans votre propre code, par exemple, certains constructeurs et les InnerExceptions de la propriété. (Vous pouvez placer votre clone dans l' System.Threading de l'espace de noms à l'intérieur de votre assemblée, ce qui pourrait causer de la confusion si vous exposé publiquement, mais que la mise à jour 4.0 plus facilement par la suite.) Lors de l' .NET 4.0 est sorti, vous devriez être en mesure de "mise à niveau" pour le Cadre type en supprimant le fichier source contenant votre clone de votre projet de modification du projet de cible de la nouvelle version de cadre, et de la reconstruction. Bien sûr, si vous faites cela, vous devez soigneusement suivre les modifications apportées à cette classe que Microsoft publie une nouvelle Ctp, de sorte que votre code n'est pas devenu incompatible. (Par exemple, il semble que cela soit utile à des fins générales de la classe, et qu'ils pourraient se déplacer d' System.Threading de System.) Dans le pire des cas, il vous suffit de renommer le type et le replacer dans votre propre espace de noms (ce qui est très facile avec la plupart des outils de refactoring).

14voto

Hath Points 5505

Deux façons du haut de ma tête seraient soit de faire une exception personnalisée et d'ajouter les exceptions à cette classe et de jeter cela à la fin:

 public class TaskExceptionList : Exception
{
    public List<Exception> TaskExceptions { get; set; }
    public TaskExceptionList()
    {
        TaskExceptions = new List<Exception>();
    }
}

    public void DoTasks(MyTask[] taskList)
    {
        TaskExceptionList log = new TaskExceptionList();
        foreach (MyTask task in taskList)
        {
            try
            {
                DoTask(task);
            }
            catch (Exception ex)
            {
                log.TaskExceptions.Add(ex);
            }
        }

        if (log.TaskExceptions.Count > 0)
        {
            throw log;
        }
    }
 

ou retourner vrai ou faux si les tâches ont échoué et ont une variable 'out List'.

     public bool TryDoTasks(MyTask[] taskList, out List<Exception> exceptions)
    {
        exceptions = new List<Exception>();
        foreach (MyTask task in taskList)
        {
            try
            {
                DoTask(task);
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
            }
        }

        if (exceptions.Count > 0)
        {
            return false;
        }
        else
        {
            exceptions = null;
            return true;
        }
    }
 

4voto

Gene Points 375

Vous pouvez créer une exception personnalisée qui elle-même possède une collection d'exceptions. Ensuite, dans votre bloc Catch, ajoutez-le simplement à cette collection. À la fin de votre processus, vérifiez si le nombre d'exceptions est> 0, puis lancez votre exception personnalisée.

2voto

Will Points 76760

Vous pouvez utiliser un BackgroundWorker pour le faire pour vous. Il capture automatiquement et présente des exceptions lorsque terminé, vous pouvez alors jeter ou de journal ou faire n'importe quoi avec. Aussi, vous obtenez l'avantage de multithreading.

Le BackgroundWorker est une belle wrapper autour de délégué du modèle de programmation asynchrone.

0voto

Cristian Libardo Points 7425

Pas de solution super élégante ici mais quelques idées:

  • Passez une fonction de gestionnaire d'erreurs comme argument aux DoTasks pour que l'utilisateur puisse décider de continuer
  • Utilisez le suivi pour consigner les erreurs lorsqu'elles se produisent
  • Concaténer les messages des autres exceptions dans le message du groupe d'exceptions

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X