A (s) exceção (ões) de uma tarefa não foram observadas por Waiting on the Task ou acessando sua propriedade Exception. Como resultado, a exceção não observada foi


100

O que isso significa e como resolver?

Estou usando tarefas TPL.

Todo o erro

A (s) exceção (ões) de uma tarefa não foram observadas por Waiting on the Task ou acessando sua propriedade Exception. Como resultado, a exceção não observada foi relançada pelo encadeamento do finalizador.

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

mscorlib

Respostas:


158

Se você criar uma Tarefa e nunca chamar task.Wait()ou tentar recuperar o resultado de uma Task<T>, quando a tarefa for coletada pelo coletor de lixo, seu aplicativo será interrompido durante a finalização. Para obter detalhes, consulte a página do MSDN sobre Tratamento de exceções na TPL .

A melhor opção aqui é "lidar" com a exceção. Isso pode ser feito por meio de uma continuação - você pode anexar uma continuação à tarefa e registrar / engolir / etc a exceção que ocorrer. Isso fornece uma maneira limpa de registrar exceções de tarefa e pode ser escrito como um método de extensão simples, ou seja:

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);
}

Com o exposto acima, você pode evitar que qualquer tarefa destrua o aplicativo e registre-o através de:

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

Como alternativa, você pode se inscrever em TaskScheduler.UnobservedTaskException e lidar com isso lá.


17
Para maior entretenimento, tenha um método stub estático Offem uma classe chamada como a palavra de quatro letras de sua escolha e use-o para suas continuações abrangentes. Ajuda a combater parte da frustração reprimida dessa exceção em particular.
— Aaronaught

1
@MonsterMMORPG Sim - você basicamente tem que capturar ou lidar com a exceção em algum lugar . Contanto que você lide com isso em algum lugar, seu problema principal irá embora.
— Reed Copsey

1
Não é possível que a tarefa possa lançar uma exceção antes que a chamada para ContinueWith seja feita?
— Tim Sylvester

1
@TimSylvester O framework ainda irá mapeá-lo através da continuação, mesmo se acontecer "antes" da continuação ser anexada
— Reed Copsey

32
Nota importante: Isso é necessário apenas para .Net 4.0. O tratamento de exceção foi alterado por padrão .net 4.5para não destruir o aplicativo . Veja mais em Manipulação de exceções de tarefas em .NET 4.5
— i3arnon

43

Certo; significa que Taskfoi finalizado após ser deixado para a coleta de lixo, mas a tarefa em si falhou. Existem duas soluções:

  • lidar com a falha de tarefas diretamente (use ContinueWith(...)para se inscrever e verificar .IsFaultede .Exceptionno Taskparâmetro)
  • manipular o TaskScheduler.UnobservedTaskExceptionevento e marcá-lo como observado (chamar e.SetObserved()após registrar o erro)

4
+1 - Com uma adição - se sua continuação não está fazendo nada além de verificar o IsFaulted, você pode usar a OnlyOnFaultedopção de continuação e evitar a verificação manual ...
— Reed Copsey

na verdade, isso aconteceu onde eu chamei uma função estática pública dentro de uma tarefa tpl. usar try catch resolveria esse problema? eu realmente preciso criar outra tarefa e esperar? obrigado
— MonsterMMORPG

4
1 para mencionar que SetObservedem UnobservedTaskExceptionEventArgsnecessidades a ser chamado.
— James Webster de

-17

Tente este:

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;
}

5
É um ??? O que você quer dizer? Você poderia explicar o que sua resposta contribui para as respostas até agora?
— Gert Arnold

você acabou de criar uma nova tarefa continuando, que irá falhar e ficar na mesma situação.
— Robert Taylor

Esta solução parece um pouco complicada. Acho que você estaria ocultando a funcionalidade sem querer, sem nenhum ganho.
— Velocitas de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.