6

LINQ を使用して、宣言的に記述したいこの簡単なループがあります。

    async Task<Foo> GetFooAsync(string fooId, CancellationToken cancellationToken = default(CancellationToken))
    {
        foreach (var source in FooSources)
        {
            var result = await source.GetFooAsync(fooId, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
            if (result != null)
            {
                return result;
            }
        }
        return null;
    }

私は次のようなものを望みます:

return FooSources.Where(...).FirstOrDefault();

特に LINQ とasync/awaitを連携させることに行き詰まっています。

4

1 に答える 1

13

LINQのオプションasyncは非常に限られています。他の回答が指摘したように、で非同期メソッドを使用できますがSelect、それだけです。

var tasks = FooSources.Select(source => source.GetFooAsync(fooId, cancellationToken));

これにより、 のシーケンスが得られますTask<Foo>。次に、それらがすべて完了するのを待ちます。

var results = await Task.WhenAll(tasks);

Fooこれで、フィルタリングできるの配列ができました。

return results.Where(foo => foo != null);

これは、元のコードとはセマンティクスが大きく異なることに注意してください。元のコードはawait、次のコードを開始する前に各ソースになります。この回答により、すべてのソースが開始され、次にすべてのソースが開始されますawait

foreachセマンティクスが必要awaitでループ内に必要な場合、正しい解決策は .foreachを含むループを使用することawaitです。LINQ に直接相当するものはありません。

于 2013-05-31T22:03:35.350 に答える