Frage

Wie erhält man in C#einen generischen Enumerator aus einem bestimmten Array?

Im Code unten, MyArray ist eine Reihe von MyType Objekte. Ich möchte erhalten MyIEnumerator in der gezeigten Art MyArray.Length > 0).

MyType [ ]  MyArray  =  ... ;
IEnumerator<MyType>  MyIEnumerator
  =  ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;
War es hilfreich?

Lösung

Funktioniert auf 2.0+:

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

Funktioniert auf 3.5+ (Fancy Linqy, etwas weniger effizient):

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

Andere Tipps

Sie können selbst entscheiden, ob Casting hässlich genug ist, um einen Frielligbibliotheksanruf zu rechtfertigen:

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 
}

Aus Vollständigkeit sollte auch beachten, dass das Folgende nicht korrekt ist-und zur Laufzeit abstürzt-weil T[] wählt die nicht-generisch IEnumerable Schnittstelle für die Standard-Implementierung (dh nicht explizit) von 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 
}

Das Geheimnis ist, warum nicht SZGenericArrayEnumerator<T> geerbt von SZArrayEnumerator-Eine interne Klasse, die derzeit als "versiegelt" gekennzeichnet ist-da dies es ermöglichen würde, dass der (kovariante) generische Enumerator standardmäßig zurückgegeben wird?

Da ich kein kleines Update gieße, kann ich nicht gießen:

your_array.AsEnumerable().GetEnumerator();

Um es so sauber wie möglich zu machen, möchte ich den Compiler gerne alle Arbeiten erledigen. Es gibt keine Abgüsse (also ist es tatsächlich Typ-Safe). Es werden keine Bibliotheken von Drittanbietern (System.LinQ) verwendet (keine Laufzeitaufwand).

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

// und um den Code zu verwenden:

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

Dies nutzt eine Compiler -Magie, die alles sauber hält.

Der andere Punkt ist, dass meine Antwort die einzige Antwort ist, die die Überprüfung der Zeit übertrifft.

Bei einer der anderen Lösungen, wenn sich der Typ "arr" ändert, wird das Aufrufen von Code kompiliert und zur Laufzeit fehlschlägt, was zu einem Laufzeitfehler führt.

Meine Antwort führt dazu, dass der Code nicht kompiliert wird, und daher habe ich weniger Chance, einen Fehler in meinen Code zu versenden, da er mir signalisieren würde, dass ich den falschen Typ verwende.

YourArray.OftType (). Getenumerator ();

Kann ein wenig besser abschneiden, da es nur den Typ überprüfen und nicht gegossen werden muss.

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

    IEnumerable<MyType> enumerable = arr;

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

    foreach (MyType item in enumerable)
    {

    }

Was Sie natürlich tun können, ist, nur Ihren eigenen generischen Enumerator für Arrays zu implementieren.

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

Dies entspricht mehr oder weniger der .NET -Implementierung von SzgenericArayenumeratoru003CT> Wie von Glenn Slayden erwähnt. Sie sollten dies natürlich nur tun, ist Fälle, in denen dies die Mühe wert ist. In den meisten Fällen ist es nicht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top