Asynchronous iterator Task>

后端 未结 3 909
遥遥无期
遥遥无期 2020-11-28 11:13

I’m trying to implement an asynchronous function that returns an iterator. The idea is the following:

    private async Task> T         


        
相关标签:
3条回答
  • 2020-11-28 11:41

    It sounds like what you may really be looking for is something like IObservable<T>, which is sort of like a push-based asynchronous IEnumerable<T>. See Reactive Extensions, a.k.a. Rx (code licensed under MIT) (no affiliation) for a huge host of methods that work with IObservable<T> to make it work like LINQ-to-Objects and more.

    The problem with IEnumerable<T> is that there's nothing that really makes the enumeration itself asynchronous. If you don't want to add a dependency on Rx (which is really what makes IObservable<T> shine), this alternative might work for you:

    public async Task<IEnumerable<char>> TestAsync(string testString)
    {
        return GetChars(testString);
    }
    
    private static IEnumerable<char> GetChars(string testString)
    {
        foreach (char c in testString.ToCharArray())
        {
            // do other work
            yield return c;
        }
    }
    

    though I'd like to point out that without knowing what's actually being done asynchronously, there may be a much better way to accomplish your goals. None of the code you posted will actually do anything asynchronously, and I don't really know if anything in // do other work is asynchronous (in which case, this isn't a solution to your underlying problem though it will make your code compile).

    0 讨论(0)
  • 2020-11-28 11:48

    A more "batteries-included" implementation of this kind of thing, including language support, is now available as of C# 8.0.

    Now, when using at least C# 8.0 (or higher) with .NET Standard 2.1 (or higher) and/or .NET Core 3.0 (or higher), the code from the original question may be written as follows:

    private async IAsyncEnumerable<char> TestAsync(string testString)
    {
        foreach (char c in testString.ToCharArray())
        {
            // do other work, which may include "await"
            yield return c;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 11:49

    To elaborate on previous answers, you can use Reactive Extensions' Observable.Create<TResult> family of methods to do exactly what you want.

    Here's an example:

    var observable = Observable.Create<char>(async (observer, cancel) =>
    {
        for (var i = 0; !cancel.IsCancellationRequested && i < 100; i++)
        {
            observer.OnNext(await GetCharAsync());
        }
    });
    

    Here's how you can use it in LINQPad, for example:

    // Create a disposable that keeps the query running.
    // This is necessary, since the observable is 100% async.
    var end = Util.KeepRunning();
    
    observable.Subscribe(
        c => Console.WriteLine(c.ToString()),
        () => end.Dispose());
    
    0 讨论(0)
提交回复
热议问题