Question

En C #, comment peut-on obtenir un recenseur générique d'un tableau donné?

Dans le code ci-dessous, MyArray est un tableau d'objets MyType. Je voudrais obtenir MyIEnumerator de la façon montré, mais il semble que j'obtenir un recenseur vide (même si je l'ai confirmé que MyArray.Length > 0).

MyType [ ]  MyArray  =  ... ;
IEnumerator<MyType>  MyIEnumerator
  =  ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;
Était-ce utile?

La solution

Travaux sur 2.0 +:

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

Travaux sur 3.5+ (LINQy fantaisie, un peu moins efficace):

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

Autres conseils

Vous pouvez décider vous-même si la coulée est assez laide pour justifier un appel de la bibliothèque étrangère:

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 
}

Et pour être complet, il convient également de noter que ce qui suit est pas correct - et va planter lors de l'exécution - car T[] choisit le non -Générique interface IEnumerable pour sa valeur par défaut (non explicite ) la mise en œuvre 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 
}

Le mystère est, pourquoi ne pas SZGenericArrayEnumerator<T> hériter de SZArrayEnumerator - une classe interne qui est actuellement marqué « fermé » - car cela permettrait au (covariant) recenseur générique doit être retourné par défaut

Depuis que je n'aime pas coulée, une petite mise à jour:

your_array.AsEnumerable().GetEnumerator();

Pour le rendre aussi propre que possible, je voudrais laisser le compilateur faire tout le travail. Il n'y a pas de moulages (de sorte que fait le type de sécurité). Aucune bibliothèque tiers (System.Linq) sont utilisés (pas de frais généraux d'exécution).

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

// Et utiliser le code:

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

profite de la magie du compilateur qui maintient tout propre.

L'autre point à noter est que ma réponse est la seule réponse qui fera la compilation de vérification.

Pour l'une des autres solutions si le type de changements « arr », puis le code d'appel va compiler et échoueront à l'exécution, ce qui entraîne un bug d'exécution.

Ma réponse provoquera le code de ne pas compiler et donc je moins de chance d'expédition d'un bug dans mon code, car il me signaler que je suis en utilisant le mauvais type.

YourArray.OfType () GetEnumerator ();.

peut effectuer un peu mieux, car il n'a qu'à vérifier le type, et non jeté.

    MyType[] arr = { new MyType(), new MyType(), new MyType() };

    IEnumerable<MyType> enumerable = arr;

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

    foreach (MyType item in enumerable)
    {

    }

Qu'est-ce que vous pouvez faire, bien sûr, est de mettre en œuvre tout votre propre recenseur générique pour les tableaux.

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. */}
    }
}

Ceci est plus ou moins égale à la implemenation .NET de SZGenericArrayEnumerator comme indiqué par Glenn Slayden. Vous devriez faire bien sûr cela est le cas où cela vaut la peine. Dans la plupart des cas, il est.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top