Les exceptions d'une tâche n'ont pas été observées en attendant la tâche ou en accédant à sa propriété Exception. En conséquence, l'exception non observée était

100

Qu'est-ce que cela signifie et comment le résoudre?

J'utilise des tâches TPL.

Toute l'erreur

Les exceptions d'une tâche n'ont pas été observées en attendant la tâche ou en accédant à sa propriété Exception. Par conséquent, l'exception non observée a été renvoyée par le thread du finaliseur.

à System.Threading.Tasks.TaskExceptionHolder.Finalize ()

mscorlib

MonstreMMORPG
la source

Réponses:

158

Si vous créez une tâche et que vous n'appelez task.Wait()ou n'essayez jamais de récupérer le résultat d'un Task<T>, lorsque la tâche est collectée par le garbage collector, votre application sera détruite lors de la finalisation. Pour plus de détails, consultez la page MSDN sur la gestion des exceptions dans le TPL .

La meilleure option ici est de "gérer" l'exception. Cela peut être fait via une continuation - vous pouvez attacher une continuation à la tâche et enregistrer / avaler / etc l'exception qui se produit. Cela fournit un moyen propre de consigner les exceptions de tâches et peut être écrit comme une simple méthode d'extension, c'est-à-dire:

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

Avec ce qui précède, vous pouvez empêcher toute tâche de détruire l'application et de la journaliser via:

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

Vous pouvez également vous abonner à l' exception TaskScheduler.UnobservedTaskException et la gérer à cet endroit .

Reed Copsey
la source
17
Pour plus de divertissement, Offutilisez une méthode stub statique dans une classe nommée comme le mot de quatre lettres de votre choix et utilisez-la pour vos continuations fourre-tout. Aide à combattre une partie de la frustration refoulée de cette exception particulière.
Aaronaught
1
@MonsterMMORPG Oui - Vous devez essentiellement attraper ou gérer l'exception quelque part . Tant que vous le gérez quelque part, votre problème central disparaîtra.
Reed Copsey
1
N'est-il pas possible que la tâche puisse lever une exception avant que l'appel à ContinueWith ne soit effectué?
Tim Sylvester
1
@TimSylvester Le framework le mappera toujours à travers la suite, même si cela se produit "avant" que la suite ne soit jointe
Reed Copsey
32
Remarque importante: Ceci n'est nécessaire que pour .Net 4.0. La gestion des exceptions a été modifiée par défaut .net 4.5pour ne pas détruire l'application . Voir plus dans Gestion des exceptions de tâches dans .NET 4.5
i3arnon
43

Sûr; cela signifie qu'un a Taskété finalisé après avoir été laissé au garbage collection, mais la tâche elle-même a échoué. Il existe deux correctifs:

  • gérer les tâches échouent directement (utilisez ContinueWith(...)pour vous abonner et vérifier .IsFaultedet .Exceptionsur le Taskdans le paramètre)
  • gérer l' TaskScheduler.UnobservedTaskExceptionévénement et le marquer comme observé (appel e.SetObserved()après avoir enregistré l'erreur)
Marc Gravell
la source
4
+1 - Avec un ajout - si votre continuation ne fait que vérifier le IsFaulted, vous pouvez utiliser l' OnlyOnFaultedoption de continuation et éviter la vérification manuelle ...
Reed Copsey
en fait, cela s'est produit lorsque j'ai appelé une fonction statique publique à l'intérieur d'une tâche tpl. utiliser try catch résoudrait ce problème? ai-je vraiment besoin de créer une autre tâche et de l'attendre? merci
MonsterMMORPG
4
+1 pour avoir mentionné que SetObservedle UnobservedTaskExceptionEventArgsdoit être appelé.
James Webster
-17

Essaye celui-là:

public static void ThrowFirstExceptionIfHappens(this Task task)
{
    task.ContinueWith(t =>
    {
        var aggException = t.Exception.Flatten();
        foreach (var exception in aggException.InnerExceptions)
        {
            throw exception; // throw only first, search for solution
        }
    },
    TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}

public static Task CreateHandledTask(Action action) 
{
    Task tsk = Task.Factory.StartNew(action);
    tsk.ThrowFirstExceptionIfHappens();
    return tsk;
}
h4165f8ghd4f854d6f8h
la source
5
C'est un ??? Que voulez-vous dire? Pourriez-vous expliquer ce que votre réponse contribue aux réponses jusqu'à présent?
Gert Arnold
vous venez de créer une nouvelle tâche en continuant qui échouera alors et entrera dans la même situation.
Robert Taylor
Cette solution semble un peu alambiquée. Je pense que vous cacheriez des fonctionnalités sans le vouloir sans aucun gain.
Velocitas