obtener enumerador genérico de una matriz


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

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

MyType [ ]  MyArray  =  ... ;
IEnumerator<MyType>  MyIEnumerator
  =  ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;
Author: John Saunders, 2009-08-13

7 answers

Funciona en 2.0+:

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

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

myArray.Cast<MyType>().GetEnumerator()   // returns IEnumerator<MyType>
 82
Author: Mehrdad Afshari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-13 15:21:48

Puede decidir por sí mismo si el casting es lo suficientemente feo como para justificar una llamada a la 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 because y se bloqueará en tiempo de ejecución because porque T[] elige la interfaz non-generic IEnumerable 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> no hereda de SZArrayEnumerator an una clase interna que actualmente está marcada como 'sellada'since ya que esto permitir que el enumerador genérico (covariante) sea devuelto por defecto?

 43
Author: Glenn Slayden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-07 22:15:14

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

your_array.AsEnumerable().GetEnumerator();
 19
Author: greenoldman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 16:10:11

Para hacerlo lo más limpio posible me gusta dejar que el compilador haga todo el trabajo. No hay moldes (por lo que en realidad es seguro). No hay bibliotecas de terceros (Sistema.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 comprobación en tiempo de compilación.

Para cualquiera de las otras soluciones si el tipo de cambios" arr", entonces el código de llamada se compilará, y fallará en tiempo de ejecución, lo que resulta en 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 el tipo incorrecto.

 4
Author: leat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-28 16:56:24

Suarray.OfType ().GetEnumerator ();

Puede funcionar un poco mejor, ya que solo tiene que comprobar el tipo, y no cast.

 1
Author: Andrew Dennison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 20:59:43
    MyType[] arr = { new MyType(), new MyType(), new MyType() };

    IEnumerable<MyType> enumerable = arr;

    IEnumerator<MyType> en = enumerable.GetEnumerator();

    foreach (MyType item in enumerable)
    {

    }
 1
Author: Maxim Q,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-11 14:48:47

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 de.NET de SZGenericArrayEnumerator como lo menciona Glenn Slayden. Por supuesto, solo debe hacer esto, es casos en los que vale la pena el esfuerzo. En la mayoría de los casos no lo es.

 0
Author: Corniel Nobel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-16 11:39:06