Tạo IAsyncEnumerable trống


25

Tôi có một giao diện được viết như thế này:

public interface IItemRetriever
{
    public IAsyncEnumerable<string> GetItemsAsync();
}

Tôi muốn viết một triển khai trống không trả về mục nào, như vậy:

public class EmptyItemRetriever : IItemRetriever
{
    public IAsyncEnumerable<string> GetItemsAsync()
    {
       // What do I put here if nothing is to be done?
    }
}

Nếu đó là một IEn Countable đơn giản, tôi sẽ return Enumerable.Empty<string>();, nhưng tôi đã không tìm thấy bất kỳ AsyncEnumerable.Empty<string>().

Cách giải quyết

Tôi thấy cái này hoạt động nhưng khá lạ:

public async IAsyncEnumerable<string> GetItemsAsync()
{
    await Task.CompletedTask;
    yield break;
}

Bất kỳ ý tưởng?

Câu trả lời:


28

Nếu bạn cài đặt System.Linq.Asyncgói, bạn sẽ có thể sử dụng AsyncEnumable.Empty<string>(). Đây là một ví dụ hoàn chỉnh:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        IAsyncEnumerable<string> empty = AsyncEnumerable.Empty<string>();
        var count = await empty.CountAsync();
        Console.WriteLine(count); // Prints 0
    }
}

Cảm ơn bạn đã trả lời nhanh chóng và đề nghị. Tôi đã hy vọng rằng một cái gì đó tồn tại trong khuôn khổ.
cube45

@ cube45: Tôi thường coi System.Linq.Asynclà "hầu như là một phần của khung". Có rất ít điều đó chỉ trong netst Chuẩn2.1 khi nói đến IAsyncEnumerable<T>.
Jon Skeet

@ cube45 Tôi sẽ cẩn thận về việc không sử dụng gói có nhiều quark với các luồng không đồng bộ mà bạn sẽ khám phá khi bạn bắt đầu sử dụng nó nhiều hơn trừ khi bạn thực sự biết bạn đang làm gì tôi thực sự sẽ ở trên nugget.
Filip Cordas

Cảm ơn câu trả lời của bạn. Tôi chưa bao giờ sử dụng IAsyncEnableable trước đây và tôi chỉ đang thử nghiệm, không làm điều gì đó "thực sự". Bạn có thể đúng, gói có thể hữu ích.
cube45

Có một vấn đề nếu nó đang được sử dụng với efcore github.com/dotnet/efcore/issues/18124
Pavel Shastov

11

Nếu vì bất kỳ lý do nào bạn không muốn cài đặt gói được đề cập trong câu trả lời của Jon, bạn có thể tạo phương thức AsyncEnumerable.Empty<T>()như sau:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public static class AsyncEnumerable
{
    public static IAsyncEnumerator<T> Empty<T>() => EmptyAsyncEnumerator<T>.Instance;

    class EmptyAsyncEnumerator<T> : IAsyncEnumerator<T>
    {
        public static readonly EmptyAsyncEnumerator<T> Instance = 
            new EmptyAsyncEnumerator<T>();
        public T Current => default!;
        public ValueTask DisposeAsync() => default;
        public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(false);
    }
}

Lưu ý: Câu trả lời không khuyến khích sử dụng System.Linq.Asyncgói. Câu trả lời này cung cấp một triển khai ngắn gọn AsyncEnumerable.Empty<T>()cho các trường hợp mà bạn cần và bạn không thể / không muốn sử dụng gói. Bạn có thể tìm thấy việc thực hiện được sử dụng trong gói ở đây .


Cảm ơn câu trả lời của bạn. Thật vậy, đó cũng là một lựa chọn. Tôi nghĩ rằng tôi thích cách đó hơn là cài đặt gói khác. Tôi sẽ đánh dấu cái này là chấp nhận. Nitpick: Bạn nói "phương thức mở rộng" trong khi nó chỉ là một phương thức tĩnh trong một lớp tĩnh.
cube45

1
@ cube45: Vì vậy, bạn không có kế hoạch sử dụng bất kỳ chức năng LINQ nào với các chuỗi không đồng bộ có liên quan? Bởi vì ngay khi bạn muốn làm bất cứ điều gì bạn thường làm với LINQ đồng bộ, bạn sẽ cần System.Linq.Async.
Jon Skeet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.