简体   繁体   中英

AggregateException C# example

I have seen an example of AggregateException on the web and I'm trying to figure out how it works. I have written a simple example, but my code for some reason doesn't work.

Could someone explain to me what the problem is?

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

You need to call Handle on the inner exceptions. From MSDN's documentation on Handle :

Each invocation of the predicate returns true or false to indicate whether the Exception was handled. After all invocations, if any exceptions went unhandled, all unhandled exceptions will be put into a new AggregateException which will be thrown. Otherwise, the Handle method simply returns. If any invocations of the predicate throws an exception, it will halt the processing of any more exceptions and immediately propagate the thrown exception as-is.

The example code, also from 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;
        });
    }
}

When using Parallel the "job" (here counting from 0 to 500000) gets split onto several worker threads. Each of these could throw an exception. In the sample the exception is coded to happen in the thread working on 10523. In a real world scenario more than one exception could happen (in different threads) - the AggregateException is just a "container" for all exceptions occuring while Parallel is running so that you don't lose any exception...

AggregateException is often used for catching exceptions, that might occur when waiting for a Task to complete. Because Task in general can consist of multiple others, we do not know, whether there will be one or more exceptions thrown.

Check the following example:

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

Here is a practical use of AggregateException to get the inner exception from an exception object,

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

My way to resolve it:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM