创建空的IAsyncEnumerable

时间:2019-12-22 10:29:12

标签: c# c#-8.0 iasyncenumerable

我有一个这样编写的接口:

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

有什么主意吗?

3 个答案:

答案 0 :(得分:21)

如果安装System.Linq.Async软件包,则应该可以使用# Working Example of how to pass parameters to sequential windows import tkinter as tk class Win1(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) self.grid() rownum = 0 colnum = 0 #-----collect some information needed for the application-------------------------- self.lbl_a = tk.Label(self, text="Number of Categories", font=("Arial Bold", 10), justify="left",anchor='w') self.lbl_a.grid(column=colnum, row=rownum,columnspan=1,sticky='w') self.numcat_ent =tk.Entry(self, width=12,background='white', fg='blue',state='normal',font=("Arial Bold", 10), justify='center') self.numcat_ent.insert('end', '4') self.numcat_ent.grid(column=colnum+1, row=rownum) numcat=int(self.numcat_ent.get()) rownum += 1 self.lbl_b = tk.Label(self, text="Items Per Category", font=("Arial Bold", 10), justify="left",anchor='w') self.lbl_b.grid(column=colnum, row=rownum,columnspan=1,sticky='w') items=6 self.numitems_ent=tk.Entry(self, width=12,background='white', fg='blue',state='normal',font=("Arial Bold", 10), justify='center') self.numitems_ent.insert('end', '4') self.numitems_ent.grid(column=colnum+1, row=rownum) numitems=int(self.numitems_ent.get()) rownum += 1 #---on click, open Win2 and close Win1 btn1=tk.Button(self,text='Show Win 2', command=lambda: self.open_win2(master,numcat ,numitems)) btn1.grid(row=rownum,column=colnum,sticky='nsew') def open_win2(self, master, numcat ,numitems): self.hide(master) self.root2 = tk.Toplevel() self.root2.geometry('300x600') print(numcat,numitems) app2 = Win2(self.root2,root, numcat, numitems) def hide(self,master): root.withdraw() #---to bring root window back #root.deiconify() class Win2(tk.Frame): def __init__(self, master, root2, parm1, parm2): tk.Frame.__init__(self, master) print(parm1, parm2) root.withdraw() self.grid() #---on click, open Win3 form and close Win2 self.btn1=tk.Button(self,text='Open Win3', command=lambda: self.open_win3(master)) self.btn1.grid(row=0,column=0) rownum = 0 colnum = 0 fontSize = 12 for i in range(parm1): rownum += 1 self.catEntry=tk.Entry(self, width=12,background='white', fg='blue',state='normal',font=("Arial Bold", fontSize), justify='center') self.catEntry.grid(column=colnum, row=rownum) for j in range(parm2): rownum += 1 self.subcatEntry=tk.Entry(self, width=12,background='white', fg='black',state='normal',font=("Arial Bold", fontSize), justify='center') self.subcatEntry.grid(column=colnum+1, row=rownum) def open_win3(self,master): self.hide(master) root3 = tk.Toplevel() root3.geometry('800x800') app3 = Win3(root3) def hide(self,master): root.withdraw() master.withdraw() class Win3(tk.Frame): def __init__(self,master): root.withdraw() tk.Frame.__init__(self, master) self.grid() self.btn=tk.Button(self,text='Return to Start Page',command=lambda:self.return_to_start(master)) self.btn.grid(row=0,column=0) def return_to_start(self, master): master.withdraw() root.deiconify() root = tk.Tk() root.geometry("225x100") app = Win1(root) #----Mainloop keeps forms updated and listens for user input-- root.mainloop() 。这是一个完整的示例:

AsyncEnumable.Empty<string>()

答案 1 :(得分:6)

如果由于某种原因您不想安装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>()的简要实现。您可以在软件包here中找到使用的实现。

答案 2 :(得分:-1)

我想避免安装新软件包,但 previous answer 实际上并未按照原始问题的要求实现 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);
    }
}