una tamaño saber recorrer qué programacion matriz matrices imprimir generar consola c# arrays generics ienumerator

c# - tamaño - obtener enumerador genérico de una matriz



recorrer matriz c# (7)

Como no me gusta el casting, una pequeña actualización:

your_array.AsEnumerable().GetEnumerator();

En C #, ¿cómo se obtiene un enumerador genérico de una matriz determinada?

En el siguiente código, MyArray es una matriz de objetos MyType . Me gustaría obtener MyIEnumerator de la manera que se muestra, pero parece que MyArray.Length > 0 un enumerador vacío (aunque he confirmado que MyArray.Length > 0 ).

MyType [ ] MyArray = ... ; IEnumerator<MyType> MyIEnumerator = ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;


Funciona en 2.0+:

((IEnumerable<MyType>)myArray).GetEnumerator()

Funciona en 3.5+ (refinado LINQy, un poco menos eficiente):

myArray.Cast<MyType>().GetEnumerator() // returns IEnumerator<MyType>


Lo que puede hacer, por supuesto, es simplemente implementar su propio enumerador genérico para matrices.

using System.Collections; using System.Collections.Generic; namespace SomeNamespace { public class ArrayEnumerator<T> : IEnumerator<T> { public ArrayEnumerator(T[] arr) { collection = arr; length = arr.Length; } private readonly T[] collection; private int index = -1; private readonly int length; public T Current { get { return collection[index]; } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { index++; return index < length; } public void Reset() { index = -1; } public void Dispose() {/* Nothing to dispose. */} } }

Esto es más o menos igual a la implementación .NET de SZGenericArrayEnumerator <T> como lo menciona Glenn Slayden. Por supuesto, solo debe hacer esto, es casos donde vale la pena el esfuerzo. En la mayoría de los casos, no lo es.


Para hacerlo lo más limpio posible, me gusta dejar que el compilador haga todo el trabajo. No hay moldes (por lo que es realmente seguro). No se utilizan bibliotecas de terceros (System.Linq) (Sin sobrecarga de tiempo de ejecución).

public static IEnumerable<T> GetEnumerable<T>(this T[] arr) { return arr; }

// Y para usar el código:

String[] arr = new String[0]; arr.GetEnumerable().GetEnumerator()

Esto aprovecha la magia del compilador que mantiene todo limpio.

El otro punto a tener en cuenta es que mi respuesta es la única respuesta que hará la verificación en tiempo de compilación.

Para cualquiera de las otras soluciones, si el tipo de "arr" cambia, entonces el código de llamada se compilará y fallará en el tiempo de ejecución, dando como resultado un error de tiempo de ejecución.

Mi respuesta hará que el código no se compile y, por lo tanto, tengo menos posibilidades de enviar un error en mi código, ya que me indicaría que estoy usando un tipo incorrecto.


Puedes decidir por ti mismo si el casting es lo suficientemente feo como para justificar una convocatoria de biblioteca extraña:

int[] arr; IEnumerator<int> Get1() { return ((IEnumerable<int>)arr).GetEnumerator(); // <-- 1 non-local call // L_0001: ldarg.0 // L_0002: ldfld int32[] foo::arr // L_0007: castclass [mscorlib]System.Collections.Generic.IEnumerable`1<int32> // L_000c: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() // L_0011: stloc.0 } IEnumerator<int> Get2() { return arr.AsEnumerable().GetEnumerator(); // <-- 2 non-local calls // L_0001: ldarg.0 // L_0002: ldfld int32[] foo::arr // L_0007: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::AsEnumerable<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>) // L_000c: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() // L_0011: stloc.0 }

Y para completar, también se debe tener en cuenta que lo siguiente no es correcto, y se bloqueará en el tiempo de ejecución, porque T[] elige la interfaz IEnumerable no genérica para su implementación predeterminada (es decir, no explícita) de GetEnumerator() .

IEnumerator<int> NoGet() // error - do not use { return (IEnumerator<int>)arr.GetEnumerator(); // L_0001: ldarg.0 // L_0002: ldfld int32[] foo::arr // L_0007: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Array::GetEnumerator() // L_000c: castclass [mscorlib]System.Collections.Generic.IEnumerator`1<int32> // L_0011: stloc.0 }

El misterio es, ¿por qué SZGenericArrayEnumerator<T> hereda de SZArrayEnumerator Una clase interna que actualmente está marcada como "sellada", ya que esto permitiría que el enumerador genérico (covariante) sea devuelto por defecto?


YourArray.OfType (). GetEnumerator ();

puede funcionar un poco mejor, ya que solo tiene que verificar el tipo, y no emitir.


MyType[] arr = { new MyType(), new MyType(), new MyType() }; IEnumerable<MyType> enumerable = arr; IEnumerator<MyType> en = enumerable.GetEnumerator(); foreach (MyType item in enumerable) { }