สร้าง IAsyncE เปล่าที่ว่างเปล่า


25

ฉันมีอินเตอร์เฟซที่เขียนแบบนี้:

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

ความคิดใด ๆ

คำตอบ:


28

หากคุณติดตั้ง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
    }
}

ขอขอบคุณสำหรับการตอบกลับอย่างรวดเร็วและข้อเสนอแนะ ฉันหวังว่าจะมีบางอย่างในกรอบ
cube45

@ cube45: โดยทั่วไปฉันจะถือว่าSystem.Linq.Asyncเป็น "ส่วนหนึ่งของกรอบงาน" มีน้อยมากที่เป็นเพียงแค่ใน netstandard2.1 IAsyncEnumerable<T>เมื่อมันมาถึง
Jon Skeet

@ cube45 ฉันจะระวังไม่ให้ใช้แพคเกจมีหลายควาร์กกับกระแส async ที่คุณจะค้นพบเมื่อคุณเริ่มใช้มันมากขึ้นเว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่
Filip Cordas

ขอบคุณสำหรับคำตอบของคุณ ฉันไม่เคยใช้ IAsyncEnumerable มาก่อนและฉันเพิ่งทดลองไม่ทำอะไรที่ "เป็นของจริง" คุณอาจถูกต้องแพคเกจอาจมีประโยชน์
cube45

มีปัญหาหากใช้กับ efcore github.com/dotnet/efcore/issues/18124
Pavel Shastov

11

ถ้าด้วยเหตุผลใดก็ตามที่คุณไม่ต้องการติดตั้งแพคเกจที่กล่าวถึงในคำตอบของจอนคุณสามารถสร้างวิธีการ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>()สำหรับกรณีที่คุณต้องการและคุณไม่สามารถ / ไม่ต้องการใช้แพคเกจ คุณสามารถค้นหาการดำเนินงานที่ใช้ในแพคเกจที่นี่


ขอบคุณสำหรับคำตอบ. แน่นอนว่าจะเป็นตัวเลือกด้วย ฉันคิดว่าฉันชอบวิธีนี้มากกว่าที่จะติดตั้งแพ็คเกจอื่น ฉันจะทำเครื่องหมายว่าสิ่งนี้เป็นที่ยอมรับ Nitpick: คุณพูดว่า "วิธีการขยาย" ในขณะที่มันเป็นเพียงวิธีการคงที่ในระดับคงที่
cube45

1
@ cube45: คุณไม่ได้วางแผนที่จะใช้ฟังก์ชัน LINQ ใด ๆ กับลำดับอะซิงโครนัสที่เกี่ยวข้องหรือไม่? เพราะทันทีที่คุณต้องการทำอะไรก็ได้ตามปกติกับ LINQ แบบซิงโครนัสคุณจะต้องใช้ System.Linq.Async
Jon Skeet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.