Исключения задачи не наблюдались ни при ожидании задачи, ни при доступе к ее свойству Exception. В результате ненаблюдаемое исключение было


100

Что это значит и как решить?

Использую задачи TPL.

Вся ошибка

Исключения задачи не наблюдались ни при ожидании задачи, ни при доступе к ее свойству Exception. В результате ненаблюдаемое исключение было повторно создано потоком финализатора.

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

mscorlib

Ответы:


158

Если вы создаете задачу и никогда не вызываете task.Wait()и не пытаетесь получить результат a Task<T>, когда задача будет собрана сборщиком мусора, он разорвет ваше приложение во время завершения. Дополнительные сведения см. На странице MSDN по обработке исключений в TPL .

Лучшим вариантом здесь является «обработать» исключение. Это можно сделать с помощью продолжения - вы можете прикрепить к задаче продолжение и зарегистрировать / проглотить и т.д. возникшее исключение. Это обеспечивает чистый способ регистрации исключений задач и может быть записан как простой метод расширения, то есть:

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

С помощью вышеуказанного вы можете предотвратить разрушение приложения и его регистрацию любой задачей с помощью:

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

Кроме того, вы можете подписаться на TaskScheduler.UnobservedTaskException и обработать его там.


17
Для дополнительного развлечения Offсоздайте статический метод-заглушку в классе, названном четырехбуквенным словом по вашему выбору, и используйте его для своих обобщающих продолжений. Помогает бороться с неудовлетворением, вызванным этим конкретным исключением.
Aaronaught

1
@MonsterMMORPG Да - вы в основном должны где-то перехватывать или обрабатывать исключение . Пока вы где-то с этим справитесь, ваша основная проблема исчезнет.
Рид Копси

1
Разве не возможно, чтобы задача могла вызвать исключение до того, как будет сделан вызов ContinueWith?
Тим Сильвестр,

1
@TimSylvester Фреймворк по-прежнему будет отображать его через продолжение, даже если это произойдет «до» прикрепления продолжения
Рид Копси,

32
Важное примечание: это необходимо только для .Net 4.0. Обработка исключений была изменена по умолчанию, .net 4.5чтобы не разрушать приложение . Дополнительные сведения см. В разделе « Обработка исключений задач в .NET 4.5»
i3arnon,

43

Конечно; это означает, что объект Taskбыл завершен после того, как был оставлен на сборку мусора, но сама задача не удалась. Есть два исправления:

  • обрабатывать задачи не в состоянии непосредственно (использование ContinueWith(...)для подписки, а также проверить .IsFaultedи .Exceptionна Taskв параметре)
  • обработать TaskScheduler.UnobservedTaskExceptionсобытие и отметить его как наблюдаемое (вызвать e.SetObserved()после регистрации ошибки)

4
+1 - С одним дополнением - если ваше продолжение ничего не делает, кроме проверки IsFaulted, вы можете использовать OnlyOnFaultedвариант продолжения и избежать ручной проверки ...
Рид Копси

на самом деле это произошло, когда я вызвал публичную статическую функцию внутри задачи tpl. использование try catch решило бы эту проблему? мне действительно нужно создать еще одну задачу и ждать ее? спасибо
MonsterMMORPG

4
+1 за упоминание , что SetObservedна UnobservedTaskExceptionEventArgsнужды называть.
Джеймс Вебстер

-17

Попробуй это:

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
Его один ??? Что вы имеете в виду? Не могли бы вы объяснить, что ваш ответ до сих пор влияет на ответы?
Герт Арнольд

вы только что создали новую задачу, продолжив выполнение, которая затем потерпит неудачу и попадет в ту же ситуацию.
Роберт Тейлор

Это решение кажется немного запутанным. Я думаю, что вы непреднамеренно скроете функциональность без какой-либо выгоды.
Velocitas
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.