2013-05-31 55 views
5

Tôi có vòng lặp đơn giản mà tôi muốn viết khai báo, sử dụng LINQ.Chuyển đổi vòng lặp không đồng bộ thành truy vấn 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; 
    } 

Tôi muốn kiếm cái gì đó trông giống như:

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

Tôi đang mắc kẹt, đặc biệt là trên làm cho LINQ và async/await làm việc cùng nhau.

+0

Bạn cũng có thể sử dụng async trong lambda :) –

+0

cài đặt chia sẻ lại và bạn có thể chuyển đổi vòng lặp đó thành biểu thức lambda –

+0

@FabianBigler: Hiển thị cho chúng tôi hình dạng trông như thế nào. –

Trả lời

13

Tùy chọn của bạn cho async LINQ rất hạn chế. Như câu trả lời khác chỉ ra, bạn có thể sử dụng phương pháp async trong Select, nhưng đó là về nó:

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

này sẽ giúp bạn có một chuỗi các Task<Foo>. Sau đó bạn có thể chờ đợi cho họ tất cả để hoàn thành:

var results = await Task.WhenAll(tasks); 

Bây giờ bạn có một mảng của Foo, mà có thể được lọc:

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

Lưu ý rằng điều này có ngữ nghĩa rất khác nhau hơn so với mã gốc của bạn. Mã ban đầu của bạn sẽ await mỗi nguồn trước khi bắt đầu tiếp theo; câu trả lời này sẽ bắt đầu tất cả các nguồn đi, và sau đó await tất cả.

Nếu bạn muốn foreach ngữ nghĩa và cần phải await bên trong vòng lặp, sau đó là giải pháp đúng là sử dụng một vòng lặp foreach chứa một await. Không có LINQ tương đương trực tiếp.

Các vấn đề liên quan