Saturday, September 20, 2014

await await Task.WhenAny

The await operator in C# automatically unwraps faulted tasks and rethrows their exceptions. You can await the completion of multiple tasks by using Task.WhenAll, and then if any of those tasks are faulted all of their exceptions will aggregated and rethrown in a single exception by the await.

However, Task.WhenAny does not work the same way as Task.WhenAll. Task.WhenAny returns an awaitable Task<Task> where the child Task represents whichever Task completed first. A key difference being that the container task will not throw when awaited!

If an exception occurs inside of a Task.WhenAny, you can automatically rethrow the exception by doing (and I realize how weird this sounds) await await Task.WhenAny

Sample Tests

[Fact]
public async Task AwaitWhenAnyWait()
{
    var t1 = Task.Run(async () =>
    {
        await Task.Delay(100);
 
        throw new InvalidOperationException();
    });
 
    // This await will NOT throw.
    var whenAny = await Task.WhenAny(t1);
 
    Assert.True(whenAny.IsFaulted);
    Assert.NotNull(whenAny.Exception);
    Assert.IsType<InvalidOperationException>(whenAny.Exception.InnerException);
}
 
[Fact]
public async Task AwaitWhenAll()
{
    var t1 = Task.Run(async () =>
    {
        await Task.Delay(100);
 
        throw new InvalidOperationException();
    });
 
    try
    {
        // This await WILL throw.
        await Task.WhenAll(t1);
 
        throw new AssertException();
    }
    catch (InvalidOperationException)
    {
    }
}
 
[Fact]
public async Task AwaitAwaitWhenAny()
{
    var t1 = Task.Run(async () =>
    {
        await Task.Delay(100);
 
        throw new InvalidOperationException();
    });
 
    try
    {
        // This await await WILL throw.
        await await Task.WhenAny(t1);
 
        throw new AssertException();
    }
    catch (InvalidOperationException)
    {
    }
}

Enjoy,
Tom

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Can I say await "Task(T)" and await await "Task(Task(T))" both throws if any exception occurs?

    ReplyDelete

Real Time Web Analytics