【问题标题】:Create empty IAsyncEnumerable创建空的 IAsyncEnumerable
【发布时间】:2019-12-22 10:29:12
【问题描述】:

我有一个这样写的界面:

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&lt;string&gt;();,但我没有找到任何AsyncEnumerable.Empty&lt;string&gt;()

解决方法

我发现这是可行的,但很奇怪:

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

有什么想法吗?

【问题讨论】:

    标签: c# c#-8.0 iasyncenumerable


    【解决方案1】:

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

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

    【讨论】:

    • @cube45:我通常将System.Linq.Async 视为“实际上是框架的一部分”。对于IAsyncEnumerable&lt;T&gt;,netstandard2.1 中只是的内容很少。
    • @cube45 我会小心不要使用这个包有很多带有异步流的夸克,当你开始更多地使用它时你会发现,除非你真的知道你在做什么我真的会在掘金上。
    • 感谢您的回答。我以前从未使用过 IAsyncEnumerable,我只是在做实验,而不是“真正地”做一些事情。你可能是对的,这个包可能有用。
    • 和efcore一起使用会有问题github.com/dotnet/efcore/issues/18124
    • 还有其他方法可以得到吗?当我安装了 Linq.Async nuget 后,对“Where”的所有调用都开始成为来自 AsyncEnumerable 和 IQueryable(来自 Entity Framework Core)的模棱两可的调用。
    【解决方案2】:

    如果出于任何原因您不想安装 Jon 的回答中提到的软件包,您可以像这样创建方法 AsyncEnumerable.Empty&lt;T&gt;()

    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&lt;T&gt;() 的简要实现,适用于您需要它并且您不能/不想使用该包的情况。您可以在包here 中找到使用的实现。

    【讨论】:

    • 感谢您的回答。事实上,这也是一种选择。我认为我更喜欢这种方式而不是安装另一个软件包。我会将此标记为已接受。 Nitpick:您说“扩展方法”,而它只是静态类中的静态方法。
    • @cube45:那么您不打算在涉及异步序列的情况下使用任何 LINQ 功能吗?因为只要您想要执行通常使用同步 LINQ 执行的任何操作,您就需要 System.Linq.Async。
    • 此代码可以返回 IAsyncEnumerator&lt;T&gt;,但不是 OP 要求的 IAsyncEnumerable&lt;T&gt;。为了实现这一点,您需要将IAsyncEnumerable&lt;T&gt; 添加到您的EmptyAsyncEnumerator&lt;T&gt; 类中,然后从您链接的代码中包含GetAsyncEnumerator 方法。
    【解决方案3】:

    我想避免安装新软件包,但 previous answer 实际上并未按照原始问题的要求实现 IAsyncEnumerable&lt;T&gt;。这是一个完整的解决方案,它实现了该接口以轻松调用AsyncEnumerable.Empty&lt;T&gt;,就像现在Enumerable.Empty&lt;T&gt; 的工作方式一样。

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

    【讨论】:

      猜你喜欢
      • 2020-06-02
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      • 2020-08-15
      • 1970-01-01
      • 2021-12-29
      相关资源
      最近更新 更多