1. ホーム
  2. c#

[解決済み] LINQを使ってタスクのリストを非同期で待ち受けるには?

2023-02-18 19:55:52

質問

このように作成したタスクのリストがあります。

public async Task<IList<Foo>> GetFoosAndDoSomethingAsync()
{
    var foos = await GetFoosAsync();

    var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList();

    ...
}

を使うことで .ToList() を使うことで、タスクはすべて開始されるはずです。あとは完了を待って結果を返せばいい。

これは、上記の ... ブロックの中で動作します。

var list = new List<Foo>();
foreach (var task in tasks)
    list.Add(await task);
return list;

これは私が望むことをやってくれますが、かなり不器用な感じがします。むしろこのようなもっとシンプルなものを書きたいのです。

return tasks.Select(async task => await task).ToList();

... しかし、これはコンパイルされません。何が足りないのでしょうか?それとも、このように表現することができないだけなのでしょうか?

どのように解決するのですか?

LINQが完全に動作しないのは async のコードでは完全に動作しませんが、このようにすることができます。

var tasks = foos.Select(DoSomethingAsync).ToList();
await Task.WhenAll(tasks);

もし、タスクがすべて同じ型の値を返すのであれば、このようなことも可能です。

var results = await Task.WhenAll(tasks);

というのは、なかなかいい感じです。 WhenAll は配列を返すので、あなたのメソッドは結果を直接返すことができると思います。

return await Task.WhenAll(tasks);