IAsyncEnumerable 或 IAsyncEnumerator 的工厂 [英] Factory for IAsyncEnumerable or IAsyncEnumerator

查看:22
本文介绍了IAsyncEnumerable 或 IAsyncEnumerator 的工厂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有办法通过 Source 对象创建 IAsyncEnumerableIAsyncEnumerator,而不是像 TaskCompletionSource 允许一个人为任务做.特别是,TaskCompletionSource 可以像任何其他参数一样传递.

I'm wondering if there is a way to create either IAsyncEnumerable<T> or IAsyncEnumerator<T> via a Source object, rather like TaskCompletionSource allows one to do for tasks. In particular, TaskCompletionSource can be passed around like any other parameter.

也许是这样的:

public class AsyncEnumerables {

    public Task HandlerTask { get; set; }

    public async Task<string> ParentMethod() {
        var source = new AsyncEnumerableSource<int>();
        IAsyncEnumerable asyncEnumerable = source.GetAsyncEnumerable();
        HandlerTask = Task.Run(() => handleAsyncResultsAsTheyHappen(asyncEnumerable));
        int n = await someOtherTask();
        source.YieldReturn(n);
        var r = await ChildMethod(source);
        source.Complete();  // this call would cause the HandlerTask to complete.
        return r;
    }

    private async Task<string> ChildMethod(AsyncEnumerableSource<int> source) {
        source.YieldReturn(5);
        await SomeOtherCall();
        source.YieldReturn(10);
        return "hello";
    }
}

使用上面的代码,handleAsyncResultsAsTheyHappen 任务会看到任何传入 YieldReturn 的值.所以它会看到上面代码中的 n,以及 ChildMethod 中的 510.

With the above code, the handleAsyncResultsAsTheyHappen task would see whatever values got passed into YieldReturn. So it would see the n from the above code, as well as the 5 and the 10 from ChildMethod.

推荐答案

如果您可以构建代码以利用 yield returnawait foreach.例如,这段代码几乎做了同样的事情:

You're much better off if you can structure your code to take advantage of yield return and await foreach. E.g., this code does almost the same thing:

public async Task Consume()
{
    var source = ParentMethod();
    HandlerTask = Task.Run(async () => { await foreach (var item in source) { Console.WriteLine(item); } });
}

public async IAsyncEnumerable<int> ParentMethod()
{
    await Task.Yield();
    yield return 13;
    await foreach (var item in ChildMethod())
        yield return item;
}

private async IAsyncEnumerable<int> ChildMethod()
{
    yield return 5;
    await Task.Yield();
    yield return 10;
}

然而,如果你真的需要一个异步可枚举源",你首先需要认识到一件事.TaskCompletionSource 保存结果,即 T(或异常).它充当一个容器.可以在等待任务之前设置结果.这与异步可枚举源"相同 - 您需要它能够在从中取出任何项目之前保存结果.异步可枚举源"需要保存多个结果 - 在这种情况下,是一个 集合.

However, if you really need an "async enumerable source", you need to first recognize one thing. TaskCompletionSource<T> holds the results, i.e., the T (or exception). It's acting as a container. The result can be set before the task is awaited. It's the same thing with the "async enumerable source" - you'd need it to be able to hold results before any items are taken from it. The "async enumerable source" would need to hold multiple results - in this case, a collection.

所以您实际上要求的是一个可以作为异步枚举使用的集合".这里有几种可能性,但我推荐的是 Channel:

So what you're actually asking for is "a collection that can be consumed as an asynchronous enumerable". There are a few possibilities here, but the one I'd recommend is a Channel:

public async Task<string> ParentMethod()
{
  var source = Channel.CreateUnbounded<int>();
  var sourceWriter = source.Writer;
  IAsyncEnumerable<int> asyncEnumerable = source.Reader.ReadAllAsync();
  HandlerTask = Task.Run(async () => { await foreach (var item in asyncEnumerable) Console.WriteLine(item); });
  await Task.Yield();
  await sourceWriter.WriteAsync(13);
  var r = await ChildMethod(sourceWriter);
  sourceWriter.Complete();
  return r;
}

private async Task<string> ChildMethod(ChannelWriter<int> sourceWriter)
{
  await sourceWriter.WriteAsync(5);
  await Task.Yield();
  await sourceWriter.WriteAsync(10);
  return "hello";
}

这篇关于IAsyncEnumerable 或 IAsyncEnumerator 的工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆