Пример AggregateException С#

Я видел пример AggregateException в сети, и я пытаюсь выяснить, как это работает. Я написал простой пример, но мой код по какой-то причине не работает.

Может ли кто-нибудь объяснить мне, в чем проблема?

public static void Main()
{
    try
    {
        Parallel.For(0, 500000, i =>
        {
            if (i == 10523)
                throw new TimeoutException("i = 10523");
            Console.WriteLine(i + "\n");
        });
    }
    catch (AggregateException exception)
    {
        foreach (Exception ex in exception.InnerExceptions)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

Ответы

Ответ 1

Вам нужно вызвать Handle для внутренних исключений. Из документации MSDN по Handle:

Каждый вызов предиката возвращает true или false, чтобы указать, было ли обработано исключение. После всех вызовов, если какие-либо исключения остались необработанными, все необработанные исключения будут помещены в новое AggregateException, которое будет выброшено. В противном случае метод Handle просто возвращается. Если какой-либо вызов предиката вызывает исключение, он останавливает обработку любых других исключений и немедленно распространяет выброшенное исключение как есть.

Пример кода, также из MSDN:

public static void Main()
{
    var task1 = Task.Run(() => { throw new CustomException("This exception is expected!"); });

    try 
    {
        task1.Wait();
    }
    catch (AggregateException ae)
    {
        // Call the Handle method to handle the custom exception,
        // otherwise rethrow the exception.
        ae.Handle(ex => 
        { 
            if (ex is CustomException)
                Console.WriteLine(ex.Message);
            return ex is CustomException;
        });
    }
}

Ответ 2

При использовании Parallel "задание" (здесь от 0 до 500000) делится на несколько рабочих потоков. Каждое из них может вызвать исключение. В образце исключение кодируется в потоке, работающем на 10523. В сценарии реального мира может произойти не одно исключение (в разных потоках) - AggregateException - это всего лишь "контейнер" для всех исключений, возникающих при запуске Parallel, чтобы вы не потеряли никакого исключения...

Ответ 3

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

Посмотрите следующий пример:

// set up your task
Action<int> job = (int i) =>
{
    if (i % 100 == 0)
        throw new TimeoutException("i = " + i);
};

// we want many tasks to run in paralell
var tasks = new Task[1000];
for (var i = 0; i < 1000; i++)
{
    // assign to other variable,
    // or it will use the same number for every task
    var j = i; 
    // run your task
    var task = Task.Run(() => job(j));
    // save it
    tasks[i] = task;
}

try
{
    // wait for all the tasks to finish in a blocking manner
    Task.WaitAll(tasks);

}
catch (AggregateException e)
{
    // catch whatever was thrown
    foreach (Exception ex in e.InnerExceptions)
        Console.WriteLine(ex.Message);
}

Ответ 5

Вот практическое использование AggregateException для получения внутреннего исключения из объекта исключения,

    private static Exception GetFirstRealException(Exception exception)
    {
        Exception realException = exception;
        var aggregateException = realException as AggregateException;

        if (aggregateException != null)
        {
            realException = aggregateException.Flatten().InnerException; // take first real exception

            while (realException != null && realException.InnerException != null)
            {
                realException = realException.InnerException;
            }
        }

        return realException ?? exception;
    }

Ответ 6

Мой способ решить это:

var tasks = new Task[] { DoSomethingAsync(), DoSomethingElseAsync() };

try
{
    await Task.WhenAll(tasks).ConfigureAwait(false);
}
catch (AggregateException ex)
{
    var flatAgrExs = ex.Flatten().InnerExceptions;

    foreach(var agrEx in flatAgrExs)
    {
        //handle out errors
        logger.LogError(agrEx, "Critical Error occurred");
    }
}