AggregateException из Task.WhenAll содержит только первое исключение при ожиданииC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 AggregateException из Task.WhenAll содержит только первое исключение при ожидании

Сообщение Anonymous »

При возникновении нескольких исключений в вызове Task.WhenAll создается впечатление, что только одно из исключений поглощается задачей Task, когда вы ожидаете ее через более чем один уровень ожидания. У меня сложилось впечатление, что свойство Task.Exception.InnerExceptions будет содержать все возникшие исключения, но при определенных обстоятельствах кажется, что у них есть только одно.

Например, этот пример кода создает несколько задач, генерирующих исключения, затем ожидает для них Task.WhenAll, а затем записывает в консоль исключения, которые он может перехватить:

Код: Выделить всё

class Program
{
static async Task Main(string[] args)
{
var task = CauseMultipleExceptionsAsync();

// Delaying until all the Exceptions have been thrown, ensuring it isn't just a weird race condition happening behind the scenes
await Task.Delay(5000);

try
{
await task;
}
catch(AggregateException e)
{
// This does not get hit
Console.WriteLine($"AggregateException caught: Found {e.InnerExceptions.Count} inner exception(s)");
}
catch(Exception e)
{
Console.WriteLine($"Caught other Exception {e.Message}");

Console.WriteLine($"task.Exception.InnerExceptions contains {task.Exception.InnerExceptions.Count} exception(s)");
foreach (var exception in task.Exception.InnerExceptions)
{
Console.WriteLine($"Inner exception {exception.GetType()}, message: {exception.Message}");
}
}
}

static async Task CauseMultipleExceptionsAsync()
{
var tasks = new List()
{
CauseExceptionAsync("A"),
CauseExceptionAsync("B"),
CauseExceptionAsync("C"),
};

await Task.WhenAll(tasks);
}

static async Task CauseExceptionAsync(string message)
{
await Task.Delay(1000);
Console.WriteLine($"Throwing exception {message}");
throw new Exception(message);
}
}
Я ожидал, что это либо войдет в предложение catch(AggregateException e), либо будет иметь по крайней мере три внутренних исключения в Task.Exception.InnerExceptions

code> — что на самом деле происходит, что возникает одно-единственное исключение, а в задаче только одно из исключений.Exception.InnerExceptions:

Код: Выделить всё

Throwing exception B
Throwing exception A
Throwing exception C
Caught other Exception A
task.Exception.InnerExceptions contains 1 exception(s)
Inner exception System.Exception, message: A
Что еще более странно, так это то, что это поведение меняется в зависимости от того, ожидаете ли вы вызова Task.WhenAll в CauseMultipleExceptionsAsync — если вы возвращаете Task напрямую вместо того, чтобы ждать его, все три исключения появляются в Task.Exception.InnerException. Например, заменив CauseMultipleExceptionsAsync на это:

Код: Выделить всё

    static Task CauseMultipleExceptionsAsync()
{
var tasks = new List()
{
CauseExceptionAsync("A"),
CauseExceptionAsync("B"),
CauseExceptionAsync("C"),
};

return Task.WhenAll(tasks);
}
Выдает этот результат со всеми тремя исключениями, содержащимися в Task.Exception.InnerExceptions:

Код: Выделить всё

Throwing exception C
Throwing exception A
Throwing exception B
Caught other Exception A
task.Exception.InnerExceptions contains 3 exception(s)
Inner exception System.Exception, message: A
Inner exception System.Exception, message: B
Inner exception System.Exception, message: C
Меня это очень смущает — куда делись исключения B и C в исходном примере? Как бы вы снова нашли их, если Task.Exception не содержит никакой информации о них? Почему ожидание внутри CauseMultipleExceptionsAsync скрывает эти исключения, а прямой возврат Task.WhenAll — нет?

Если это имеет значение, я способен повторить вышеизложенное как в .Net Framework 4.5.2, так и в .Net Core 2.1.

Подробнее здесь: https://stackoverflow.com/questions/613 ... en-awaited
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»