How to handle exceptions when using Task Parallel Library Task.WhenAny ()

When I use the function Task.WhenAll()and the exception is raised in the Task, a new AggregateException event is raised, I can catch it to see all the exceptions that occurred in the Task. However, when I use Task.WhenAny(), an exception is not thrown. Instead, I should check the property Task.Exceptionfor the value to see if an exception has occurred. This seems like a bad code smell, as I would have to forget to check the property Task.Exceptionevery time I use Task.WhenAny(). Shouldn't there be a better way?

Here is an example of what I mean:

private async void btnMultipleExceptions_Click(object sender, EventArgs e) {
        var task1 = ThrowNotImplementedException();
        var task2 = ThrowDivideByZeroException();

        try {
            Task task = await Task.WhenAny(task1, task2);

            // Even if an exception is thrown in one of the tasks (in our case,
            // task1 will throw first) no exception is thrown from
            // the above await Task.WhenAny(). Instead, the exception is placed on the 
            // Task.Exception property. So I need to check for it every time 
            // I call Task.WhenAny()?
            if (task.Exception != null) {
                Console.WriteLine("Exceptions: " + string.Join(Environment.NewLine,
                    task.Exception.InnerExceptions.Select(x => x.Message).ToArray()));
            } else {
                Console.WriteLine("No Exceptions!");
            }
        } catch(Exception ex) {
            // Try to catch all exceptions???
            AggregateException allEx = ex as AggregateException;

            if (allEx != null) {
                Console.WriteLine("Exceptions: " + string.Join(Environment.NewLine,
                    allEx.InnerExceptions.Select(x => x.Message).ToArray()));
            } else {
                Console.WriteLine("Exceptions: " + ex.Message);
            }
        }
    }

    private async Task ThrowNotImplementedException() {
        await Task.Delay(TimeSpan.FromSeconds(1));
        throw new NotImplementedException();
    }

    private async Task ThrowDivideByZeroException() {
        await Task.Delay(TimeSpan.FromSeconds(2));
        throw new DivideByZeroException();
    }
+5
source share
3 answers

await WhenAny. , , , , , .

Unwrap Task.WhenAny, await. ; , , .

, WhenAny, , , :

public static Task WhenAny(IEnumerable<Task> tasks)
{
    return Task.WhenAny(tasks).Unwrap();
}
public static Task<T> WhenAny<T>(IEnumerable<Task<T>> tasks)
{
    return Task.WhenAny(tasks).Unwrap();
}
//TODO add wrappers for the `params` overloads if you want them too
+2

. 2- , .NET 4.5 , GC'd, . - Continuations ( , WhenAny() , ). - :

private static void LogIfErrors(Task source)
{
    if(source.Exception == null) return;
    source.Exception.Handle(ex =>
    {
        Log.Error("#unhandled #task #error", ex);
        return true;
    });
    return;
}

private void DoStuff()
{
    // note that you cannot inline the ContinueWith() statement,
    // because it would change the value of task1 to hold your
    // continuation instead of your parent task

    var task1 = ThrowNotImplementedException();
    task1.ContinueWith(LogIfErrors, TaskContinuationOptions.OnlyOnFaulted);

    var task2 = ThrowDivideByZeroException();
    task2.ContinueWith(LogIfErrors, TaskContinuationOptions.OnlyOnFaulted);

    var firstCompleted = await Tasks.WhenAny(task1, task2).Unwrap();

}

, , , WhenAny(), ( < =.NET 4.0) .

+2

await await Task.WhenAny(...);
0

Source: https://habr.com/ru/post/1589485/


All Articles