40

我有一个这样写的界面:

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

我想编写一个不返回任何项目的空实现,如下所示:

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

如果它是一个普通的 IEnumerable,我会return Enumerable.Empty<string>();,但我没有找到任何AsyncEnumerable.Empty<string>().

解决方法

我发现这行得通,但很奇怪:

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

任何想法?

4

3 回答 3

46

如果你安装了这个System.Linq.Async包,你应该可以使用AsyncEnumable.Empty<string>(). 这是一个完整的例子:

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
    }
}
于 2019-12-22T10:45:56.850 回答
17

如果出于任何原因您不想安装 Jon 的回答中提到的软件包,您可以创建如下方法AsyncEnumerable.Empty<T>()

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);
    }
}

注意:答案并不阻止使用该System.Linq.Async软件包。AsyncEnumerable.Empty<T>()这个答案为您需要它并且您不能/不想使用该包的情况提供了一个简短的实现。您可以在此处找到包中使用的实现。

于 2019-12-22T11:33:01.167 回答
2

我想避免安装新软件包,但之前的答案实际上并未IAsyncEnumerable<T>按照原始问题中的要求实现。这是一个完整的解决方案,它实现了该接口,以便以与今天AsyncEnumerable.Empty<T>相同的方式轻松调用。Enumerable.Empty<T>

public static class AsyncEnumerable
{
    /// <summary>
    /// Creates an <see cref="IAsyncEnumerable{T}"/> which yields no results, similar to <see cref="Enumerable.Empty{TResult}"/>.
    /// </summary>
    public static IAsyncEnumerable<T> Empty<T>() => EmptyAsyncEnumerator<T>.Instance;

    private class EmptyAsyncEnumerator<T> : IAsyncEnumerator<T>, IAsyncEnumerable<T>
    {
        public static readonly EmptyAsyncEnumerator<T> Instance = new EmptyAsyncEnumerator<T>();
        public T Current => default;
        public ValueTask DisposeAsync() => default;
        public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            return this;
        }
        public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(false);
    }
}
于 2021-05-14T16:05:27.583 回答