Shimmy Weitzhandler
Shimmy Weitzhandler

Reputation: 104841

Task.WhenAny ContinueWith: Get argument?

I want to execute a list of tasks, and perform a synchronous action once any of them is completed, but I need to know which of them it was.

See my example, and look out for the comment in the code, that precedes a couple of lines I don't know how to achieve.

public async Task<bool> GreetAsync(string name)
{
  if (name == null)
    return false;

  await InternalGreeter.GreetAsync(name);
  return true;
}

public async Task GreetAllAsync()
{
  var tasks = UserNames.Select(un => GreetAsync(un)).ToList();

  while(tasks.Any())
  {
    var finished = await Task.WhenAny(tasks);

    if(finished.Result)
    {
      //Here's what I'd like to achieve
      var username = finished.Arguments[0];
      WriteLine($"User {username} has been greeted.");
    }

    tasks.Remove(finished);
  } 
}

Based on this example.

In my real world scenario, I have a list of customers, which I have to walk thru them one by one and update a remote server on their credit status (the remote server doesn't support batch updates). After each of them has been updated, I have to mark in my database, that this customer has been accredited.

Upvotes: 4

Views: 943

Answers (2)

DavidG
DavidG

Reputation: 119206

Why not simply use ContinueWith? Something like this:

public async Task GreetAllAsync(List<string> UserNames)
{
  var tasks = UserNames
    .Select(un => GreetAsync(un)
        .ContinueWith(x => {
            Console.WriteLine(un + " has been greeted");
        }));

    await Task.WhenAll(tasks);
}

Upvotes: -1

Stephen Cleary
Stephen Cleary

Reputation: 457472

You almost never want to actually process a list of tasks one at a time as they complete like that. Instead, just introduce a higher-level operation and rewrite your Task.WhenAny to a Task.WhenAll to wait for those higher-level operations.

public async Task<bool> GreetAsync(string name)
{
  if (name == null)
    return false;

  await InternalGreeter.GreetAsync(name);
  return true;
}

private async Task<bool> GreetAndReportGreetedAsync(string name)
{
  var result = await GreetAsync(name);
  WriteLine($"User {name} has been greeted.");
  return result;
}

public async Task GreetAllAsync()
{
  await Task.WhenAll(UserNames.Select(un => GreetAsync(un));
}

Upvotes: 6

Related Questions