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}