recorrer getenumerator c# .net

getenumerator - recorrer un ienumerable c#



¿Tiene dot net una interfaz como IEnumerable con una propiedad Count? (10)

¿Tiene dot net una interfaz como IEnumerable con una propiedad count? Sé sobre interfaces como IList e ICollection que sí ofrecen una propiedad Count, pero parece que estas interfaces fueron diseñadas para estructuras de datos mutables primero y su uso como interfaz de solo lectura parece una ocurrencia tardía: la presencia de un campo IsReadOnly y mutadores arrojando excepciones cuando esta propiedad es cierta, hay una amplia evidencia de la OMI para esto.

Por el momento estoy usando una interfaz personalizada llamada IReadOnlyCollection (vea mi propia respuesta a esta publicación) pero me gustaría saber de otros enfoques alternativos.


Como menciona Jon Skeet, es mucho mejor utilizar System.Collections.ObjectModel.ReadOnlyCollection en lugar de crear su propia clase contenedora.

Luego puede implementar su muestra de la siguiente manera:

class Program { static void Main(string[] args) { List<int> list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); list.Add(4); ReadOnlyCollection<int> collection = new ReadOnlyCollection<int>(list); Console.WriteLine("Count:{0}", collection.Count); foreach (var x in collection) { Console.WriteLine(x); } foreach (var x in (IEnumerable)collection) { Console.WriteLine(x); } } }


Como se trata de una interfaz, debería implementar la propiedad Count usted mismo, ¿por qué no crea una nueva interfaz que hereda IEnumerator y agrega una propiedad Count?


IList puede devolver IsReadOnly como verdadero, que marca la colección como de solo lectura. Aparte de eso, me temo que no sé nada apropiado.


La diferencia clave entre la familia ICollection y la familia IEnumerable es la falta de certeza en cuanto al recuento de elementos presentes (con frecuencia los elementos se generarán / cargarán / hidratarán según sea necesario) - en algunos casos, un Enumerable puede no terminar de generar resultados, que es por lo que el conde falta.

Derivar y agregar un conteo es posible dependiendo de sus requisitos, pero va en contra de este espíritu, que es el propósito de ICollection, una colección de cosas que están ahí.

Otra forma podría ser utilizar el método System.Linq.Enumerable.Count, es decir,

using System.Linq; class X { void Y(IEnumerable<int> collection) { int itemCount = collection.Count(); } }

o use el (System.Linq.Enumerable) .ToList () para extraer todos los elementos del enumerador a una Colección y trabajar desde allí.

(También para responder a su comentario antes de tener 50 repeticiones: - el bit ".Count ()" es una llamada a un método de extensión en la clase de extensión System.Linq.Enumerable - el método de extensión está disponible en todos los elementos que se derivan de IEnumerable porque el código tiene un "using System.Linq" que pone los métodos de extensión en todas las clases en ese espacio de nombres en el alcance - en este caso está en la clase Enumerable. Si estás en VS, presionando F12 te llevará a la definición de SLEnumerable . BTW C # In Depth es un libro fantástico para aprender LINQ correctamente - es un turner de página que realmente te ayuda a obtener una imagen completa en comparación con aprender los bits de LINQ pieza por pieza)


Parece que realmente solo quieres ReadOnlyCollection<T> , exponerlo como IList<T> , pero ajustando la lista original de esta manera solo obtienes un contenedor de solo lectura con un conteo apropiado.


Puede obtener .Count en IEnumerable con un método de extensión si agrega una referencia a System.Linq (en 3.5 de todos modos).


Una matriz se puede convertir a un IList, lo que hace que IList ReadOnly == true :)


IList o ICollection sería el camino a seguir, si desea utilizar las interfaces estándar.

Tenga en cuenta que puede "ocultar" los métodos requeridos por la interfaz si no los quiere en la interfaz pública de su clase; por ejemplo, dado que no tiene sentido agregar elementos a una colección de solo lectura, puede hacer esto:

void ICollection<DataType>.Add(DataType item) { throw new NotSupportedException(); } public DataType this[int index] { get { return InnerList[index]; } } DataType IList<DataType>.this[int index] { get { return this[index]; } set { throw new NotSupportedException(); } }

etc.


A partir de .Net 4.5, hay dos nuevas interfaces para esto: IReadOnlyCollection<T> e IReadOnlyList<T> .

IReadOnlyCollection<T> es IEnumerable<T> con una propiedad Count añadida, IReadOnlyList<T> también agrega indexación.


Tomando en consideración algunos de los comentarios que he decidido incluir en una clase de contenedor implementando una interfaz personalizada ...

interface IReadOnlyCollection<T> : IEnumerable<T> { int Count { get; } } //This can now be not misused by downcasting to List //The wrapper can also be used with lists since IList inherits from ICollection public class CollectionWrapper<T> : IReadOnlyCollection<T> { public CollectionWrapper(ICollection<T> collection) { _collection = collection; } public int Count { get { return _collection.Count; } } public IEnumerator<T> GetEnumerator() { return (IEnumerator<T>)_collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)((IEnumerable)_collection).GetEnumerator(); } ////////Private data/////// ICollection<T> _collection; } class Program { static void Main(string[] args) { List<int> list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); list.Add(4); CollectionWrapper<int> collection = new CollectionWrapper<int>(list); Console.WriteLine("Count:{0}", collection.Count); foreach (var x in collection) { Console.WriteLine(x); } foreach (var x in (IEnumerable)collection) { Console.WriteLine(x); } } }

Gracias a todos por sus sugerencias.

Editar: Ahora no se puede usar incorrectamente bajando a Lista (o lo que sea).