How to convert an existing List/Collection to IAsyncEnumerable [duplicate] - c#

I'm incrementally introducing Ix.NET into a legacy project. I have a number of storage-level APIs that return Task<IEnumerable<T>>, but I want to adapt them to IAsyncEnumerable<T> for consumption in the rest of the system. It seems like there should be a helper method (ala .ToAsyncEnumerable() for IEnumerable) to help with this, but I can't find anything... Do I have to implement my own custom Enumerator? (not hard, but I don't want to re-invent the wheel)

Task<IEnumerable<T>> GetSomeResults<T>()
{
throw new NotImplementedException();
}
async IAsyncEnumerable<T> GetAsyncEnumerable<T>()
{
var results = await GetSomeResults<T>();
foreach(var item in results)
{
yield return item;
}
}

If you're talking about web APIs, Task<IEnumerable<T>> is an asynchronous way of producing a IEnumerable<T>.
Regardless of that IEnumerable<T> being produced synchronously or asynchronously, the whole list will be sent as an HTTP response.
The way you could leverage IAsyncEnumerable<T> on the client is if that client is invoking some kind of streaming or making multiple requests to a server for a unique list of results (paging).

I was looking for the exact same thing, and due to the replies here I assume that there is indeed no method like AsAsyncEnumerable(). So here's what I ended up doing, maybe it helps soneone else:
public static class AsyncEnumerableExtensions {
public struct AsyncEnumerable<T> : IAsyncEnumerable<T> {
private readonly IEnumerable<T> enumerable;
public AsyncEnumerable(IEnumerable<T> enumerable) {
this.enumerable = enumerable;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
return new AsyncEnumerator<T>(enumerable?.GetEnumerator());
}
}
public struct AsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> enumerator;
public AsyncEnumerator(IEnumerator<T> enumerator) {
this.enumerator = enumerator;
}
public ValueTask DisposeAsync() {
enumerator?.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(enumerator == null ? false : enumerator.MoveNext());
}
public T Current => enumerator.Current;
}
public static AsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> that) {
return new AsyncEnumerable<T>(that);
}
public static AsyncEnumerator<T> AsAsyncEnumerator<T>(this IEnumerator<T> that) {
return new AsyncEnumerator<T>(that);
}
}

As commented by Theodor Zoulias,
System.Linq.Async is a NuGet package from .NET Foundation, which supports ToAsyncEnumerable().
Example usage:
var tasks = new Task[0]; // get your IEnumerable<Task>s
tasks.ToAsyncEnumerable();

public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
using IEnumerator<T> enumerator = enumerable.GetEnumerator();
while (await Task.Run(enumerator.MoveNext).ConfigureAwait(false))
{
yield return enumerator.Current;
}
}

Related

How can I "adapt" a Task<IEnumerable<T>> to IAsyncEnumerable<T>?

I'm incrementally introducing Ix.NET into a legacy project. I have a number of storage-level APIs that return Task<IEnumerable<T>>, but I want to adapt them to IAsyncEnumerable<T> for consumption in the rest of the system. It seems like there should be a helper method (ala .ToAsyncEnumerable() for IEnumerable) to help with this, but I can't find anything... Do I have to implement my own custom Enumerator? (not hard, but I don't want to re-invent the wheel)
Task<IEnumerable<T>> GetSomeResults<T>()
{
throw new NotImplementedException();
}
async IAsyncEnumerable<T> GetAsyncEnumerable<T>()
{
var results = await GetSomeResults<T>();
foreach(var item in results)
{
yield return item;
}
}
If you're talking about web APIs, Task<IEnumerable<T>> is an asynchronous way of producing a IEnumerable<T>.
Regardless of that IEnumerable<T> being produced synchronously or asynchronously, the whole list will be sent as an HTTP response.
The way you could leverage IAsyncEnumerable<T> on the client is if that client is invoking some kind of streaming or making multiple requests to a server for a unique list of results (paging).
I was looking for the exact same thing, and due to the replies here I assume that there is indeed no method like AsAsyncEnumerable(). So here's what I ended up doing, maybe it helps soneone else:
public static class AsyncEnumerableExtensions {
public struct AsyncEnumerable<T> : IAsyncEnumerable<T> {
private readonly IEnumerable<T> enumerable;
public AsyncEnumerable(IEnumerable<T> enumerable) {
this.enumerable = enumerable;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
return new AsyncEnumerator<T>(enumerable?.GetEnumerator());
}
}
public struct AsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> enumerator;
public AsyncEnumerator(IEnumerator<T> enumerator) {
this.enumerator = enumerator;
}
public ValueTask DisposeAsync() {
enumerator?.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(enumerator == null ? false : enumerator.MoveNext());
}
public T Current => enumerator.Current;
}
public static AsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> that) {
return new AsyncEnumerable<T>(that);
}
public static AsyncEnumerator<T> AsAsyncEnumerator<T>(this IEnumerator<T> that) {
return new AsyncEnumerator<T>(that);
}
}
As commented by Theodor Zoulias,
System.Linq.Async is a NuGet package from .NET Foundation, which supports ToAsyncEnumerable().
Example usage:
var tasks = new Task[0]; // get your IEnumerable<Task>s
tasks.ToAsyncEnumerable();
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
using IEnumerator<T> enumerator = enumerable.GetEnumerator();
while (await Task.Run(enumerator.MoveNext).ConfigureAwait(false))
{
yield return enumerator.Current;
}
}

Error with duck enumeration for IAsyncEnumerable in System.Interactive.Async

I wonder why this code for IAsyncEnumerable<>
dynamic duckAsyncEnumerable = new int[0].ToAsyncEnumerable();
var duckAsyncEnumerator = duckAsyncEnumerable.GetEnumerator();
raises an exception:
'object' does not contain a definition for 'GetEnumerator'
Same code for IEnumerable<> works fine.
Moreover inplementation for IAsyncEnumerable<> via reflection works fine too.
Reproduced in .NET and .NET Core.
This code needed for IOutputFormatter implementation that get source data as object and have to iterate through it.
described example in dotnetfiddle
Calling new int[0].ToAsyncEnumerable() will return the (internal) type AsyncIListEnumerableAdapter<int>. This type implements among other things IEnumerable<int> so it has the method IEnumerable<int>.GetEnumerator(). However, it implements this method using explicit interface implementation.
An interface method that is explicitly implemented is not available when you call through dynamic (it is private). To access the method you will have to cast the reference to the interface first as explained in this answer to the question Use explicit interface implementations with a dynamic object.
I got the solution. An object have extension method ToAsyncEnumerable which returns IAsyncEnumerable<object>. Thus we can iterate over it:
public async Task Process(object source)
{
using (var enumerator = source.ToAsyncEnumerable().GetEnumerator())
{
while (await enumerator.MoveNext())
{
var item = enumerator.Current;
}
}
}
One can create wrapper that takes IAsyncEnumerable<T> and implements IAsyncEnumerable<object>. Activator creates that wrapper in extension method. Here is the implementation:
public class AsyncEnumerable<T> : IAsyncEnumerable<object>
{
private IAsyncEnumerable<T> _source;
public AsyncEnumerable(IAsyncEnumerable<T> source)
{
_source = source;
}
public IAsyncEnumerator<object> GetEnumerator()
{
return new AsyncEnumerator<T>(_source.GetEnumerator());
}
}
public class AsyncEnumerator<T> : IAsyncEnumerator<object>
{
private IAsyncEnumerator<T> _source;
public AsyncEnumerator(IAsyncEnumerator<T> source)
{
_source = source;
}
public object Current => _source.Current;
public void Dispose()
{
_source.Dispose();
}
public async Task<bool> MoveNext(CancellationToken cancellationToken)
{
return await _source.MoveNext(cancellationToken);
}
}
public static class AsyncEnumerationExtensions
{
public static IAsyncEnumerable<object> ToAsyncEnumerable(this object source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
else if (!source.GetType().GetInterfaces().Any(i => i.GetGenericTypeDefinition() == typeof(IAsyncEnumerable<>)))
{
throw new ArgumentException("IAsyncEnumerable<> expected", nameof(source));
}
var dataType = source.GetType()
.GetInterfaces()
.First(i => i.GetGenericTypeDefinition() == typeof(IAsyncEnumerable<>))
.GetGenericArguments()[0];
var collectionType = typeof(AsyncEnumerable<>).MakeGenericType(dataType);
return (IAsyncEnumerable<object>)Activator.CreateInstance(collectionType, source);
}
}

How can I turn an enumerable into an AsyncEnumerable?

I have some code that uses the async extension methods available in Entity Framework Core:
public async Task<MyResult> DoQuery<T>(IQueryable<T> queryable)
{
var count = await queryable.CountAsync();
var firstItems = await queryable
.Take(5)
.ToArrayAsync();
return new MyResult(count, firstItems);
}
This works great when the IQueryable I give the function comes straight from EF. I also wanted to reuse this code to do some logic on a LINQ-to-objects "query":
var evens = Enumerable.Range(0, 10).Where(i => i % 2 == 0);
var result = DoQuery(evens.AsQueryable());
This fails (which isn't too surprising):
System.InvalidOperationException: The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
It looks like a refactor is in order, but I'm curious: is there any way to turn a plain enumerable into a "dummy" AsyncEnumerable or AsyncQueryable that treats CountAsync synchronously?
You need to create an in-memory DbAsyncQueryProvider to process the async query. There is a detailed explanation on how to do that here. Scroll to the part about Testing with async queries. Below is the code copy & pasted from that link:
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace TestingDemo
{
internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal TestDbAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new TestDbAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestDbAsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute(expression));
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
public TestDbAsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public TestDbAsyncEnumerable(Expression expression)
: base(expression)
{ }
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
IQueryProvider IQueryable.Provider
{
get { return new TestDbAsyncQueryProvider<T>(this); }
}
}
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current
{
get { return _inner.Current; }
}
object IDbAsyncEnumerator.Current
{
get { return Current; }
}
}
}
This may not have been available when the question was asked. It might not cater for the specific EF situation you are asking for. To directly answer the title of your question: "How can I turn an enumerable into an AsyncEnumerable?" or the one in the body of your question: "turn a plain enumerable into a "dummy" AsyncEnumerable...?"
The System.Linq namespace has native support for ToAsyncEnumerable() which does the job (there are several overloads)
If that was not available for whatever reason, you could implement it yourself like so:
public static async IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> input)
{
foreach(var value in input)
{
yield return value;
}
}

How to create IEnumerable<T> on which multiple enumerations are not possible?

When I enumerate over an IEnumerable twice Resharper complains about Possible multiple enumerations of IEnumerable. I know, in some case of DB-queries when you enumerate twice you get an exception.
I want to reproduce that behavior in tests. So, I basically want the following function to throw (because of multiple enumerations):
private void MultipleEnumerations(IEnumerable<string> enumerable)
{
MessageBox.Show(enumerable.Count().ToString());
MessageBox.Show(enumerable.Count().ToString());
}
What should I pass to it? All the Lists, Collections etc. are ok with multiple enumerations.
Even this kind of IEnumerable doesn't give an exception:
private IEnumerable<string> GetIEnumerable()
{
yield return "a";
yield return "b";
}
Thanks.
You probably just want a custom class:
public class OneShotEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _source;
private bool _shouldThrow = false;
public OneShotEnumerable(IEnumerable<T> source)
{
this._source = source;
}
public IEnumerator<T> GetEnumerator()
{
if (_shouldThrow) throw new InvalidOperationException();
_shouldThrow = true;
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Create your own class that implements IEnumerable<T> and throw an exception if GetEnumerator() is called twice (use a boolean instance field).
Alternatively, create an iterator that uses a flag field to ensure that it cannot be called twice (enumerating an iterator twice will execute the entire method twice).
The custom class, which I've copied from John Gietzen's answer (with a couple of corrections), could usefully be combined with an extension method to create a really simple way to do this.
public class OneShotEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> source;
private bool shouldThrow = false;
public OneShotEnumerable(IEnumerable<T> source)
{
this.source = source;
}
public IEnumerator<T> GetEnumerator()
{
if (shouldThrow)
throw new InvalidOperationException("This enumerable has already been enumerated.");
shouldThrow = true;
return this.source.GetEnumerator();
}
}
public static clas OneShotEnumerableExtension
{
public static IEnumerable<T> SingleUse<T>(this IEnumerable<T> source)
{
#if (DEBUG)
return new OneShotEnumerableExtension(source);
#else
return source;
#endif
}
}
Then you can pass something to your previous method by simply doing
MultipleEnumerations(MyEnumerable.SingleUse());

Is there a built-in way to convert IEnumerator to IEnumerable

Is there a built-in way to convert IEnumerator<T> to IEnumerable<T>?
The easiest way of converting I can think of is via the yield statement
public static IEnumerable<T> ToIEnumerable<T>(this IEnumerator<T> enumerator) {
while ( enumerator.MoveNext() ) {
yield return enumerator.Current;
}
}
compared to the list version this has the advantage of not enumerating the entire list before returning an IEnumerable. using the yield statement you'd only iterate over the items you need, whereas using the list version, you'd first iterate over all items in the list and then all the items you need.
for a little more fun you could change it to
public static IEnumerable<K> Select<K,T>(this IEnumerator<T> e,
Func<K,T> selector) {
while ( e.MoveNext() ) {
yield return selector(e.Current);
}
}
you'd then be able to use linq on your enumerator like:
IEnumerator<T> enumerator;
var someList = from item in enumerator
select new classThatTakesTInConstructor(item);
You could use the following which will kinda work.
public class FakeEnumerable<T> : IEnumerable<T> {
private IEnumerator<T> m_enumerator;
public FakeEnumerable(IEnumerator<T> e) {
m_enumerator = e;
}
public IEnumerator<T> GetEnumerator() {
return m_enumerator;
}
// Rest omitted
}
This will get you into trouble though when people expect successive calls to GetEnumerator to return different enumerators vs. the same one. But if it's a one time only use in a very constrained scenario, this could unblock you.
I do suggest though you try and not do this because I think eventually it will come back to haunt you.
A safer option is along the lines Jonathan suggested. You can expend the enumerator and create a List<T> of the remaining items.
public static List<T> SaveRest<T>(this IEnumerator<T> e) {
var list = new List<T>();
while ( e.MoveNext() ) {
list.Add(e.Current);
}
return list;
}
EnumeratorEnumerable<T>
A threadsafe, resettable adaptor from IEnumerator<T> to IEnumerable<T>
I use Enumerator parameters like in C++ forward_iterator concept.
I agree that this can lead to confusion as too many people will indeed assume Enumerators are /like/ Enumerables, but they are not.
However, the confusion is fed by the fact that IEnumerator contains the Reset method. Here is my idea of the most correct implementation. It leverages the implementation of IEnumerator.Reset()
A major difference between an Enumerable and and Enumerator is, that an Enumerable might be able to create several Enumerators simultaneously. This implementation puts a whole lot of work into making sure that this never happens for the EnumeratorEnumerable<T> type. There are two EnumeratorEnumerableModes:
Blocking (meaning that a second caller will simply wait till the first enumeration is completed)
NonBlocking (meaning that a second (concurrent) request for an enumerator simply throws an exception)
Note 1: 74 lines are implementation, 79 lines are testing code :)
Note 2: I didn't refer to any unit testing framework for SO convenience
using System;
using System.Diagnostics;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace EnumeratorTests
{
public enum EnumeratorEnumerableMode
{
NonBlocking,
Blocking,
}
public sealed class EnumeratorEnumerable<T> : IEnumerable<T>
{
#region LockingEnumWrapper
public sealed class LockingEnumWrapper : IEnumerator<T>
{
private static readonly HashSet<IEnumerator<T>> BusyTable = new HashSet<IEnumerator<T>>();
private readonly IEnumerator<T> _wrap;
internal LockingEnumWrapper(IEnumerator<T> wrap, EnumeratorEnumerableMode allowBlocking)
{
_wrap = wrap;
if (allowBlocking == EnumeratorEnumerableMode.Blocking)
Monitor.Enter(_wrap);
else if (!Monitor.TryEnter(_wrap))
throw new InvalidOperationException("Thread conflict accessing busy Enumerator") {Source = "LockingEnumWrapper"};
lock (BusyTable)
{
if (BusyTable.Contains(_wrap))
throw new LockRecursionException("Self lock (deadlock) conflict accessing busy Enumerator") { Source = "LockingEnumWrapper" };
BusyTable.Add(_wrap);
}
// always implicit Reset
_wrap.Reset();
}
#region Implementation of IDisposable and IEnumerator
public void Dispose()
{
lock (BusyTable)
BusyTable.Remove(_wrap);
Monitor.Exit(_wrap);
}
public bool MoveNext() { return _wrap.MoveNext(); }
public void Reset() { _wrap.Reset(); }
public T Current { get { return _wrap.Current; } }
object IEnumerator.Current { get { return Current; } }
#endregion
}
#endregion
private readonly IEnumerator<T> _enumerator;
private readonly EnumeratorEnumerableMode _allowBlocking;
public EnumeratorEnumerable(IEnumerator<T> e, EnumeratorEnumerableMode allowBlocking)
{
_enumerator = e;
_allowBlocking = allowBlocking;
}
private LockRecursionPolicy a;
public IEnumerator<T> GetEnumerator()
{
return new LockingEnumWrapper(_enumerator, _allowBlocking);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class TestClass
{
private static readonly string World = "hello world\n";
public static void Main(string[] args)
{
var master = World.GetEnumerator();
var nonblocking = new EnumeratorEnumerable<char>(master, EnumeratorEnumerableMode.NonBlocking);
var blocking = new EnumeratorEnumerable<char>(master, EnumeratorEnumerableMode.Blocking);
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
try
{
var willRaiseException = from c1 in nonblocking from c2 in nonblocking select new {c1, c2};
Console.WriteLine("Cartesian product: {0}", willRaiseException.Count()); // RAISE
}
catch (Exception e) { Console.WriteLine(e); }
foreach (var c in nonblocking) Console.Write(c); // OK (implicit Reset())
foreach (var c in blocking) Console.Write(c); // OK (implicit Reset())
try
{
var willSelfLock = from c1 in blocking from c2 in blocking select new { c1, c2 };
Console.WriteLine("Cartesian product: {0}", willSelfLock.Count()); // LOCK
}
catch (Exception e) { Console.WriteLine(e); }
// should not externally throw (exceptions on other threads reported to console)
if (ThreadConflictCombinations(blocking, nonblocking))
throw new InvalidOperationException("Should have thrown an exception on background thread");
if (ThreadConflictCombinations(nonblocking, nonblocking))
throw new InvalidOperationException("Should have thrown an exception on background thread");
if (ThreadConflictCombinations(nonblocking, blocking))
Console.WriteLine("Background thread timed out");
if (ThreadConflictCombinations(blocking, blocking))
Console.WriteLine("Background thread timed out");
Debug.Assert(true); // Must be reached
}
private static bool ThreadConflictCombinations(IEnumerable<char> main, IEnumerable<char> other)
{
try
{
using (main.GetEnumerator())
{
var bg = new Thread(o =>
{
try { other.GetEnumerator(); }
catch (Exception e) { Report(e); }
}) { Name = "background" };
bg.Start();
bool timedOut = !bg.Join(1000); // observe the thread waiting a full second for a lock (or throw the exception for nonblocking)
if (timedOut)
bg.Abort();
return timedOut;
}
} catch
{
throw new InvalidProgramException("Cannot be reached");
}
}
static private readonly object ConsoleSynch = new Object();
private static void Report(Exception e)
{
lock (ConsoleSynch)
Console.WriteLine("Thread:{0}\tException:{1}", Thread.CurrentThread.Name, e);
}
}
}
Note 3: I think the implementation of the thread locking (especially around BusyTable) is quite ugly; However, I didn't want to resort to ReaderWriterLock(LockRecursionPolicy.NoRecursion) and didn't want to assume .Net 4.0 for SpinLock
Solution with use of Factory along with fixing cached IEnumerator issue in JaredPar's answer allows to change the way of enumeration.
Consider a simple example: we want custom List<T> wrapper that allow to enumerate in reverse order along with default enumeration. List<T> already implements IEnumerator for default enumeration, we only need to create IEnumerator that enumerates in reverse order. (We won't use List<T>.AsEnumerable().Reverse() because it enumerates the list twice)
public enum EnumerationType {
Default = 0,
Reverse
}
public class CustomList<T> : IEnumerable<T> {
private readonly List<T> list;
public CustomList(IEnumerable<T> list) => this.list = new List<T>(list);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
//Default IEnumerable method will return default enumerator factory
public IEnumerator<T> GetEnumerator()
=> GetEnumerable(EnumerationType.Default).GetEnumerator();
public IEnumerable<T> GetEnumerable(EnumerationType enumerationType)
=> enumerationType switch {
EnumerationType.Default => new DefaultEnumeratorFactory(list),
EnumerationType.Reverse => new ReverseEnumeratorFactory(list)
};
//Simple implementation of reverse list enumerator
private class ReverseEnumerator : IEnumerator<T> {
private readonly List<T> list;
private int index;
internal ReverseEnumerator(List<T> list) {
this.list = list;
index = list.Count-1;
Current = default;
}
public void Dispose() { }
public bool MoveNext() {
if(index >= 0) {
Current = list[index];
index--;
return true;
}
Current = default;
return false;
}
public T Current { get; private set; }
object IEnumerator.Current => Current;
void IEnumerator.Reset() {
index = list.Count - 1;
Current = default;
}
}
private abstract class EnumeratorFactory : IEnumerable<T> {
protected readonly List<T> List;
protected EnumeratorFactory(List<T> list) => List = list;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public abstract IEnumerator<T> GetEnumerator();
}
private class DefaultEnumeratorFactory : EnumeratorFactory {
public DefaultEnumeratorFactory(List<T> list) : base(list) { }
//Default enumerator is already implemented in List<T>
public override IEnumerator<T> GetEnumerator() => List.GetEnumerator();
}
private class ReverseEnumeratorFactory : EnumeratorFactory {
public ReverseEnumeratorFactory(List<T> list) : base(list) { }
public override IEnumerator<T> GetEnumerator() => new ReverseEnumerator(List);
}
}
As Jason Watts said -- no, not directly.
If you really want to, you could loop through the IEnumerator<T>, putting the items into a List<T>, and return that, but I'm guessing that's not what you're looking to do.
The basic reason you can't go that direction (IEnumerator<T> to a IEnumerable<T>) is that IEnumerable<T> represents a set that can be enumerated, but IEnumerator<T> is a specific enumeratation over a set of items -- you can't turn the specific instance back into the thing that created it.
static class Helper
{
public static List<T> SaveRest<T>(this IEnumerator<T> enumerator)
{
var list = new List<T>();
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
return list;
}
public static ArrayList SaveRest(this IEnumerator enumerator)
{
var list = new ArrayList();
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
return list;
}
}
Nope, IEnumerator<> and IEnumerable<> are different beasts entirely.
This is a variant I have written... The specific is a little different. I wanted to do a MoveNext() on an IEnumerable<T>, check the result, and then roll everything in a new IEnumerator<T> that was "complete" (so that included even the element of the IEnumerable<T> I had already extracted)
// Simple IEnumerable<T> that "uses" an IEnumerator<T> that has
// already received a MoveNext(). "eats" the first MoveNext()
// received, then continues normally. For shortness, both IEnumerable<T>
// and IEnumerator<T> are implemented by the same class. Note that if a
// second call to GetEnumerator() is done, the "real" IEnumerator<T> will
// be returned, not this proxy implementation.
public class EnumerableFromStartedEnumerator<T> : IEnumerable<T>, IEnumerator<T>
{
public readonly IEnumerator<T> Enumerator;
public readonly IEnumerable<T> Enumerable;
// Received by creator. Return value of MoveNext() done by caller
protected bool FirstMoveNextSuccessful { get; set; }
// The Enumerator can be "used" only once, then a new enumerator
// can be requested by Enumerable.GetEnumerator()
// (default = false)
protected bool Used { get; set; }
// The first MoveNext() has been already done (default = false)
protected bool DoneMoveNext { get; set; }
public EnumerableFromStartedEnumerator(IEnumerator<T> enumerator, bool firstMoveNextSuccessful, IEnumerable<T> enumerable)
{
Enumerator = enumerator;
FirstMoveNextSuccessful = firstMoveNextSuccessful;
Enumerable = enumerable;
}
public IEnumerator<T> GetEnumerator()
{
if (Used)
{
return Enumerable.GetEnumerator();
}
Used = true;
return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T Current
{
get
{
// There are various school of though on what should
// happens if called before the first MoveNext() or
// after a MoveNext() returns false. We follow the
// "return default(TInner)" school of thought for the
// before first MoveNext() and the "whatever the
// Enumerator wants" for the after a MoveNext() returns
// false
if (!DoneMoveNext)
{
return default(T);
}
return Enumerator.Current;
}
}
public void Dispose()
{
Enumerator.Dispose();
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public bool MoveNext()
{
if (!DoneMoveNext)
{
DoneMoveNext = true;
return FirstMoveNextSuccessful;
}
return Enumerator.MoveNext();
}
public void Reset()
{
// This will 99% throw :-) Not our problem.
Enumerator.Reset();
// So it is improbable we will arrive here
DoneMoveNext = true;
}
}
Use:
var enumerable = someCollection<T>;
var enumerator = enumerable.GetEnumerator();
bool res = enumerator.MoveNext();
// do whatever you want with res/enumerator.Current
var enumerable2 = new EnumerableFromStartedEnumerator<T>(enumerator, res, enumerable);
Now, the first GetEnumerator() that will be requested to enumerable2 will be given through the enumerator enumerator. From the second onward the enumerable.GetEnumerator() will be used.
The other answers here are ... strange. IEnumerable<T> has just one method, GetEnumerator(). And an IEnumerable<T> must implement IEnumerable, which also has just one method, GetEnumerator() (the difference being that one is generic on T and the other is not). So it should be clear how to turn an IEnumerator<T> into an IEnumerable<T>:
// using modern expression-body syntax
public class IEnumeratorToIEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerator<T> Enumerator;
public IEnumeratorToIEnumerable(IEnumerator<T> enumerator) =>
Enumerator = enumerator;
public IEnumerator<T> GetEnumerator() => Enumerator;
IEnumerator IEnumerable.GetEnumerator() => Enumerator;
}
foreach (var foo in new IEnumeratorToIEnumerable<Foo>(fooEnumerator))
DoSomethingWith(foo);
// and you can also do:
var fooEnumerable = new IEnumeratorToIEnumerable<Foo>(fooEnumerator);
foreach (var foo in fooEnumerable)
DoSomethingWith(foo);
// Some IEnumerators automatically repeat after MoveNext() returns false,
// in which case this is a no-op, but generally it's required.
fooEnumerator.Reset();
foreach (var foo in fooEnumerable)
DoSomethingElseWith(foo);
However, none of this should be needed because it's unusual to have an IEnumerator<T> that doesn't come with an IEnumerable<T> that returns an instance of it from its GetEnumerator method. If you're writing your own IEnumerator<T>, you should certainly provide the IEnumerable<T>. And really it's the other way around ... an IEnumerator<T> is intended to be a private class that iterates over instances of a public class that implements IEnumerable<T>.

Categories

Resources