WhenAny and Pattern Matching with Different Types of Task

I recently hit a scenario where I wanted to query two different datastores at the same time, but all I wanted was the first answer - it didn’t matter to me which returned first. In a later post, I will show how to do that, but for now I’m keeping this example simple.

I have two async methods, one that returns a string and one that returns an int, both with a random delay built in to simulate calling out to a data store.

public static async Task<int> GetIntAsync()
{
    await Task.Delay(random.Next(100, 500));
    return 123;
}

public static async Task<string> GetStringAsync()
{
    await Task.Delay(random.Next(100, 500));
    return "123456789";
}

I call GetIntAsync and GetStringAsync asynchronously and await the two tasks -

Task<int> getIntTask = GetIntAsync();
Task<string> getStringTask = GetStringAsync();

var result = await Task.WhenAny(getIntTask, getStringTask);

Then with a bit of pattern matching (thanks Andrew Lock for the suggestion), I can tell which one finished and extract the value I need.

if (result is Task<int> intTask)
{
    int value = await intTask;
    Console.WriteLine($"GetIntAsync completed first: {value}");
}
else if (result is Task<string> stringTask)
{
    string value = await stringTask;
    Console.WriteLine($"GetStringAsync completed first: {value}");
}

For ease of reading, here is the full source code -

 1using System;
 2using System.Threading.Tasks;
 3                    
 4public class Program
 5{
 6    public static async Task Main()
 7    {
 8        Task<int> getIntTask = GetIntAsync();
 9        Task<string> getStringTask = GetStringAsync();
10
11        var result = await Task.WhenAny(getIntTask, getStringTask);
12
13        if (result is Task<int> intTask)
14        {
15            int value = await intTask;
16            Console.WriteLine($"GetIntAsync completed first: {value}");
17        }
18        else if (result is Task<string> stringTask)
19        {
20            string value = await stringTask;
21            Console.WriteLine($"GetStringAsync completed first: {value}");
22        }
23    }
24    
25    public static async Task<int> GetIntAsync()
26    {
27        await Task.Delay(random.Next(100, 500));
28        return 123;
29    }
30    
31    public static async Task<string> GetStringAsync()
32    {
33        await Task.Delay(random.Next(100, 500));
34        return "123456789";
35    }
36
37    static Random random = new Random();
38}
comments powered by Disqus

Related