C# 实现IEnumerable包含异步/等待任务

C# 实现IEnumerable包含异步/等待任务,c#,async-await,task,C#,Async Await,Task,我想创建一个容器,每当我想要获取它的项目时(迭代),它都会延迟将项目返回给我。真的,我想要实现多种延迟(计时器延迟+返回每个项目后的延迟+返回某些项目后的延迟) 但我在下面的例子中简化了这个想法下面的代码可以工作,但是当我使用wait Task.Delay(…)时出现问题。我在代码中描述了它(请阅读注释) 问题: 有没有一种方法可以用GetEnumerator方法来实现它,以防止阻塞迭代MyContainer对象的线程 你有什么有趣的方法来实现这个想法(任何有趣的解决方案)?:) 我认为很明

我想创建一个容器,每当我想要获取它的项目时(迭代),它都会延迟将项目返回给我。真的,我想要实现多种延迟(计时器延迟+返回每个项目后的延迟+返回某些项目后的延迟)

但我在下面的例子中简化了这个想法下面的代码可以工作,但是当我使用
wait Task.Delay(…)
时出现问题。我在代码中描述了它(请阅读注释)

问题:

  • 有没有一种方法可以用
    GetEnumerator
    方法来实现它,以防止阻塞迭代
    MyContainer对象的线程
  • 你有什么有趣的方法来实现这个想法(任何有趣的解决方案)?:)
我认为很明显,我希望在
IEnumerable
中隐藏和嵌入延迟机制

我不会在我的高水平课程的主体中列出一个简单的
foreach

我想制作一个带有嵌入延迟机制的容器,最后只需在MyContainer上使用
foreach
而不需要任何延迟(如bellow测试)


从概念上来说,这应该能让你获得大部分的方法,你可以调整它

其思想是它不阻塞,但每个产生的值都可以通过可控的延迟等待

public static IEnumerable<Task<T>> EnumerateWithDelay<T>(Func<int, T> generator, Func<int, T, bool> limiter, TimeSpan delay)
{
    var idx = 0;
    while (true)
    {
        var item = generator(idx);
        if (!limiter(idx, item)) yield break;
        yield return Task.Delay(delay).ContinueWith(_ => item);
        idx++;
    }
}

public async Task A()
{
    foreach (var itemTask in EnumerateWithDelay(idx => idx, (idx, val) => idx < 10, TimeSpan.FromSeconds(0.5)))
    {
        // I'll take .5 seconds
        var number = await itemTask;
    }
}
公共静态IEnumerable Enumerated WithDelay(函数生成器、函数限制器、时间跨度延迟)
{
var-idx=0;
while(true)
{
var项目=发电机(idx);
如果(!限制器(idx,项目))产量中断;
收益返回任务。延迟(延迟)。继续(=>item);
idx++;
}
}
公共异步任务A()
{
foreach(EnumerateWithDelay中的var itemTask(idx=>idx,(idx,val)=>idx<10,TimeSpan.FromSeconds(0.5)))
{
//我要1.5秒
var编号=等待项任务;
}
}

稍加调整,可以使生成器函数在延迟结束后才被调用。

不清楚您要做什么。您希望迭代器包含延迟,但不希望
foreach
延迟?听起来您需要的延迟/计时器可能应该在堆栈的不同部分实现。顺便说一句,如果您使用
IAsyncEnumerable
的实现,那么将异步/等待和可枚举混合起来会更容易,例如:@natebarbetini,您的
IAsyncEnumerable
链接很有趣!你可以在这里写下你的评论并举例作为回答吗?我认为,如果将来其他人希望像我一样混合使用
IEnumerable
Task
s,那么在这个问题页面上,这将对他们有所帮助。链接:有助于(a)创建元素提供程序,由于对其他异步事件(如等待句柄、网络流)的依赖性,生成元素可能需要大量时间;(b)一个消费者,在这些元素准备就绪后立即处理这些元素,而不阻塞线程(处理安排在工作线程上)。
var myCnt=new MyContainer(new List<int>() {10,20,30,40,50}, 2);
var sw=new Stopwatch();
sw.Start();

foreach (var item in myCnt)
{
    Trace.WriteLine(sw.Elapsed);
}

sw.Stop();

// Result:
// 00:00:02.0014343
// 00:00:04.0034690
// 00:00:06.0045362
// 00:00:08.0056571
// 00:00:10.0067891
public static IEnumerable<Task<T>> EnumerateWithDelay<T>(Func<int, T> generator, Func<int, T, bool> limiter, TimeSpan delay)
{
    var idx = 0;
    while (true)
    {
        var item = generator(idx);
        if (!limiter(idx, item)) yield break;
        yield return Task.Delay(delay).ContinueWith(_ => item);
        idx++;
    }
}

public async Task A()
{
    foreach (var itemTask in EnumerateWithDelay(idx => idx, (idx, val) => idx < 10, TimeSpan.FromSeconds(0.5)))
    {
        // I'll take .5 seconds
        var number = await itemTask;
    }
}