que español enum c# iterator ienumerator

español - Implementar un enumerador bidireccional en C#



enum class c# (7)

¿Hay alguna manera de utilizar bloques de rendimiento para implementar un IEnumerator<T> que pueda ir hacia atrás ( MoveLast() ) y hacia adelante?


No directamente desde el bloque iterador, no.

Sin embargo, la persona que llama siempre puede almacenar los resultados, por ejemplo, en una List<T> , o simplemente llamar a Reverse() , pero esto no siempre se aplica.


No, la máquina de estados generada por el compilador C # es estrictamente hacia adelante.

No tiene sentido retroceder en muchos casos. Imagínese un iterador que lee de un flujo de red: para ir hacia atrás, tendría que recordar todo lo que había leído, porque no podía rebobinar el tiempo y volver a solicitar a la red los datos.

(Igual que cualquier cosa que haya generado datos de una manera con pérdidas. Imagine un iterador que devuelve una nueva placa para la vida de Conway en cada iteración; hay varias tablas que podrían haber sido todas las anteriores , así que para ir hacia atrás nuevamente debe recordar lo que Ya he regresado.)


No. Una de las limitaciones de IEnumerator es que mantiene su estado actual y no recuerda su estado anterior. Como resultado, IEnumerable es solo para reenvío.

Si necesita aferrarse a estados anteriores, lea IEnumerable en una Lista o LinkedList y enumere a través de esos objetos en su lugar.


En realidad, parece haber un enfoque descrito en Accelerated C # 2008 . Lamentablemente, dos páginas no son visibles en la vista previa y deben basarse en la reflexión (cuyos resultados pueden almacenarse en la memoria caché, como de costumbre) pero puede obtener la esencia.


La biblioteca de colecciones C5 ( http://www.itu.dk/research/c5/ ) implementa colecciones y lista vinculada con enumeración hacia atrás. El proyecto es OpenSource por lo que debería poder encontrar la respuesta allí.



Sé que este hilo es muy viejo, pero es relevante tener en cuenta que

foreach(var item in someCollection) { // Do something }

... se compila en:

var enumerator = someCollection.GetEnumerator() while (enumerator.MoveNext()) { var item = enumerator.Current; // Do something }

Entonces, si no le importa la sintaxis "MoveNext", puede implementar fácilmente IEnumerator y agregar un "MovePrevious". No podría invertir la dirección si usa "foreach", pero podría revertir la dirección si usa un ciclo while.

O ... si quiere "foreach" una lista en sentido inverso (no bidireccional) puede aprovechar la declaración de rendimiento.

public static IEnumerable<TItem> Get<TItem>(IList<TItem> list) { if (list == null) yield break; for (int i = list.Count - 1; i > -1; i--) yield return list[i]; }

O ... si quiere foreach en reversa siguiendo la ruta larga, puede implementar su propio IEnumerable / IEnumerator

public static class ReverseEnumerable { public static IEnumerable<TItem> Get<TItem>(IList<TItem> list) { return new ReverseEnumerable<TItem>(list); } } public struct ReverseEnumerable<TItem> : IEnumerable<TItem> { private readonly IList<TItem> _list; public ReverseEnumerable(IList<TItem> list) { this._list = list; } public IEnumerator<TItem> GetEnumerator() { if (this._list == null) return Enumerable.Empty<TItem>().GetEnumerator(); return new ReverseEnumator<TItem>(this._list); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } public struct ReverseEnumator<TItem> : IEnumerator<TItem> { private readonly IList<TItem> _list; private int _currentIndex; public ReverseEnumator(IList<TItem> list) { this._currentIndex = list.Count; this._list = list; } public bool MoveNext() { if (--this._currentIndex > -1) return true; return false; } public void Reset() { this._currentIndex = -1; } public void Dispose() { } public TItem Current { get { if (this._currentIndex < 0) return default(TItem); if (this._currentIndex >= this._list.Count) return default(TItem); return this._list[this._currentIndex]; } } object IEnumerator.Current { get { return this.Current; } } }