Skip to content

Instantly share code, notes, and snippets.

@DCCoder90
Last active September 2, 2023 18:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save DCCoder90/d358ace7ef36401dd6f0449d4ab87706 to your computer and use it in GitHub Desktop.
Save DCCoder90/d358ace7ef36401dd6f0449d4ab87706 to your computer and use it in GitHub Desktop.
Convert IEnumerable to IAsyncEnumerable It has come to my attention that this is at the top of google search results. Before attempting to use this please read the comments below. This is old, and outdated. The comments contain better solutions. TL&DR: use System.Linq.Async's ToAsyncEnumerable()
public static class AsyncEnumerableExtensions
{
public static IAsyncEnumerable<TResult> SelectAsync<T, TResult>(this IEnumerable<T> enumerable,
Func<T, Task<TResult>> selector)
{
return AsyncEnumerable.CreateEnumerable(() =>
{
var enumerator = enumerable.GetEnumerator();
var current = default(TResult);
return AsyncEnumerable.CreateEnumerator(async c =>
{
var moveNext = enumerator.MoveNext();
current = moveNext
? await selector(enumerator.Current).ConfigureAwait(false)
: default(TResult);
return moveNext;
},
() => current,
() => enumerator.Dispose());
});
}
}
@masaab
Copy link

masaab commented Apr 15, 2020

Good one mate

@MelbourneDeveloper
Copy link

@DCCoder90

Hi. Where would we get the method CreateEnumerator? It doesn't seem to exist on AsyncEnumerable out of the box. Is it an extension method?

@masaab
Copy link

masaab commented Jul 15, 2020

You can use https://www.nuget.org/packages/AsyncEnumerator/ if you like or System.Collections.Generic.AsyncEnumerator

@MelbourneDeveloper
Copy link

MelbourneDeveloper commented Jul 15, 2020

@masaab same issue.

There is no CreateEnumerator method

@masaab
Copy link

masaab commented Jul 15, 2020

I mean @DCCoder90 might be using extension methods but its possible to use the above nuget package to get the same results you can also use System.Collections.Generic.AsyncEnumerator.Create.

@MelbourneDeveloper
Copy link

@masaab that method takes different parameters.

@masaab
Copy link

masaab commented Jul 15, 2020

A quicky the System.Collections.Generic.AsyncEnumerator.Create take 3 arguments 1. A Func of movenext, 2. A Func of Current, 3. A Func of Dispose. Its same as @DCCoder90 CreateEnumerable.

If you need another example you could follow the example in the link https://www.nuget.org/packages/AsyncEnumerator/ it is not usingSystem.Collections.Generic.AsyncEnumerator.Create but the example is much cleaner.

@DCCoder90
Copy link
Author

@MelbourneDeveloper This was using an Ix.net extension method. More details may be found at
https://stu.dev/iasyncenumerable-introduction/

However this is fairly old currently and would be best to use alternative methods. I would recommend using the approach @masaab mentioned above.

@chrismortega
Copy link

This worked for me

public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
    foreach(var item in enumerable)
    {
        yield return await Task.FromResult(item);
    }
} 

@chrismortega
Copy link

Ok. Well the above only works if you can use c# 8. If not you can do this:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace YourCoolNamespace
{
    public static class AsyncEnumerableExtensions
    {
        public static IAsyncEnumerable<T> ToAsyncEnumerable<T>(IEnumerable<T> enumerable) =>
            new SynchronousAsyncEnumerable<T>(enumerable);

        private class SynchronousAsyncEnumerable<T> : IAsyncEnumerable<T>
        {
            private readonly IEnumerable<T> _enumerable;

            public SynchronousAsyncEnumerable(IEnumerable<T> enumerable) =>
                _enumerable = enumerable;

            public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) =>
                new SynchronousAsyncEnumerator<T>(_enumerable.GetEnumerator());
        }

        private class SynchronousAsyncEnumerator<T> : IAsyncEnumerator<T>
        {
            private readonly IEnumerator<T> _enumerator;

            public T Current => _enumerator.Current;

            public SynchronousAsyncEnumerator(IEnumerator<T> enumerator) =>
                _enumerator = enumerator;

            public ValueTask DisposeAsync() =>
                new ValueTask(Task.CompletedTask);

            public ValueTask<bool> MoveNextAsync() =>
                new ValueTask<bool>(Task.FromResult(_enumerator.MoveNext()));
        }
    }
}

@MelbourneDeveloper
Copy link

MelbourneDeveloper commented May 7, 2021

You can do it like this with System.Linq.Async

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TestProject3
{
    public static class AsyncExtensions
    {
        public static IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerator<T> enumerator)
        =>
            AsyncEnumerable.Create((cancellationToken)
                => AsyncEnumerator.Create(
                    () => new ValueTask<bool>(enumerator.MoveNext()),
                    () => enumerator.Current,
                    () => new ValueTask())
            );
    }

}

@Magnus12
Copy link

Magnus12 commented May 14, 2021

But in AsyncEnumerable in System.Linq.Async there already is a ToAsyncEnumerable function.
https://github.com/dotnet/reactive/blob/main/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToAsyncEnumerable.cs

@MelbourneDeveloper
Copy link

Well, glad to know I was on the right track. If that's the case, why did this gist come up when I Googled for this?

@IanKemp
Copy link

IanKemp commented Jul 21, 2021

Well, glad to know I was on the right track. If that's the case, why did this gist come up when I Googled for this?

AFAIK Google doesn't index GitHub repos directly because source code changes too frequently, but it does index Gists which are relatively static.

@fschwiet
Copy link

Consider updating the git description with a "TL&DR: use System.Linq.Async's ToAsyncEnumerable()"

Personally I thought it'd be called AsAsyncEnumerable() and turned to Google after that didn't exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment