2009-10-20 18 views
9

Se ha preguntado un par de veces sobre SO cómo puede implementar un enumerador bidireccional (here, here). Mi pregunta no es cómo (que es trivial para la mayoría de los casos), pero por qué no existe ese tipo en la plataforma .NET.¿Por qué .NET no tiene un enumerador bidireccional?

public interface IBidirectionalEnumerator<T> : IEnumerator<T> 
{ 
    bool MovePrev(); 
} 

Obviamente, hay muchos tipos de colección que no puede implementar esto, como MoveNext() es destructivo o cambia el estado de la colección subyacente. Pero a la inversa, muchos tipos pueden implementar esto trivialmente (List, IList, LinkedList, array).

¿Por qué no existe ese tipo?

+4

Hay algo muy incorrecto en el diseño de su colección si al enumerarlo cambia su estado. – Joren

+0

de acuerdo. Pero de hecho hay algunas colecciones que deberían cambiar al enumerar, como una pila o una cola. –

+2

A menos que use IEnumerable envuelto sobre un tipo de transmisión o un recurso del sistema como un StreamReader o una lista de archivos. –

Respuesta

3
  • IEnumerator es compatible con la sentencia C# foreach y con las construcciones de bucle de otros idiomas.
  • No hay ninguna instrucción o lenguaje de programación común que permita IBidirectionalEnumerator.
+1

Esto no es completamente cierto. C# solo requiere que funcionen el método 'MoveNext' y la propiedad' Current'. No depende en absoluto de la interfaz. –

+3

En realidad 'IEnumerator ' no es necesario para 'foreach'. Siempre y cuando su clase tenga un método 'GetEnumerator()' que no tome parámetros y devuelva un objeto que tenga un 'objeto Actual {get; } 'propiedad y un método' void MoveNext() ', luego' foreach' funcionará muy feliz con él. –

+0

Greg: ¿De verdad? Entonces, ¿el IEnumerator está efectivamente escrito a pato? Esa es una revelación. –

2

Porque, o nadie pensó en ello, o nadie pensó que sería particularmente útil o porque no había suficiente presupuesto o ...

En realidad no es necesario, ¿verdad? Usted mismo puede implementarlo fácilmente. Quizás el equipo de BCL pensó que no valía la pena implementarlo, probarlo, documentarlo, etc. Nunca subestimes el costo de una función, puede sonar "fácil", pero tiene costos.

Particular porque una única interfaz que nadie implementa parece extraña, ¿no? Es de esperar que List, Array, etc. implementen la interfaz, que al final es bastante trabajo.

+0

Heh, como ICloneable. = P –

+0

Como diría Raymond Chen, todas las características comienzan con -100 puntos. –

1

Además, ¿cuál sería la motivación para esto? Soporte de idioma para la iteración "hacia atrás"?

El patrón de iterador no le da mucho peso al concepto de "direccionalidad" de un conjunto de elementos. Es un patrón simple para proporcionar una interfaz simple para iterar sobre un conjunto.

4

Cuando diseña un marco, debe tomar decisiones sobre cómo hacer cosas en diferentes niveles de abstracción. La desventaja es que si elige exponer las cosas a un nivel de abstracción alto, logrará la generalización a costa de perder el control detallado sobre las cosas. Si elige exponer cosas a niveles de abstracción más bajos, su concepto no podrá generalizarse también, pero puede controlar los detalles en un nivel inferior.

Es una decisión de diseño. La implementación de ambos será costosa y hará que el marco esté más inflado y deberá soportar ambos al agregar funciones. Deberá conservar la compatibilidad con versiones anteriores en el futuro. No es una buena idea agregar todo lo que se le ocurra al BCL sin asegurarse de que tenga un beneficio significativo.

2

Obviamente, hay muchos tipos de colección que no puede implementar esto, como MoveNext() es destructivo o cambia el estado de la colección subyacente.

MoveNext() no es destructivo.De hecho, si el estado de la colección subyacente se cambia entre el momento en que se creó el IEnumerator y el momento en que se llama al MoveNext(), la llamada al MoveNext() fallará.

El objetivo de IEnumerator es iterar una vez en todos los elementos de una colección, en el orden nativo de la colección, si la colección tiene una orden nativa. IEnumerator no pretende ser un dispositivo de navegación de recopilación, como uno podría encontrar en C++.

1

Una pregunta más importante es por qué .Net no implementa IReadableByIndex, que a su vez sería heredado por IList. Tal tipo no habría agregado nada al trabajo requerido para producir implementaciones IList de lectura/escritura, y habría reducido el trabajo requerido para producir implementaciones de solo lectura (que implementaría IReadableByIndex, en lugar de IList).

No es demasiado útil para reflexionar sobre este tipo de "por qué", sin embargo. .Net es lo que es. La única forma de remediar la situación para .Net 5.0 sería permitir un medio para declarar que una interfaz que implementa una propiedad de lectura-escritura puede implementar implícitamente una versión de solo lectura (para permitir que IList herede una covariante). IReadableByIndex sin tener que agregar un método Get explícito).

Cuestiones relacionadas