Frage

Kann mir jemand sagen, warum der folgende Code nicht die Art und Weise funktioniert ich erwarten? Ich versuche, eine IEnumberable Wrapper um einen Stream zu schreiben, aber wenn ich ElementAt darauf verwenden, liest sie sequentielle Zeichen aus dem Strom unabhängig vom Index I zu ElementAt passieren.

Die Datei "test.txt" enthält "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Ich würde erwarten, dass die ausgegeben werden:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaa
  bbbbbbbbbbbbbbbbbbbbbbbbbbb
  ...

Stattdessen erhalte ich

  

ABCDEFGHIJKLMNOPQRSTUVWXYZ

und ArgumentOutOfRangeException wird aufgerufen, obwohl der einzige Index ich ElementAt bestanden habe bisher 0 ist.

MSDN sagt:

  

Wenn die Art der Quelle implementiert IList <(Of <(T>)>), dass die Umsetzung verwendet wird, um das Element am angegebenen Index zu erhalten. Andernfalls erhält diese Methode das angegebene Element.

Sollte das lesen "erhält die nächsten Element"? Wenn ja, besiegt, dass irgendwie den Zweck der faulen Listen ...

    static IEnumerable<char> StreamOfChars(StreamReader sr)
    {
        while (!sr.EndOfStream)
            yield return (char)sr.Read();
    }


    static void Main(string[] args)
    {
        using (StreamReader sr = new StreamReader("test.txt"))
        {
            IEnumerable<char> iec = StreamOfChars(sr);

            for (int i = 0; i < 26; ++i)
            {
                for (int j = 0; j < 27; ++j)
                {
                    char ch = iec.ElementAt(i);
                    Console.Write(ch);
                }
                Console.WriteLine();
            }
        }
    }
War es hilfreich?

Lösung

Ja, sollte die MSDN-Dokumentation lesen „erhält das nächste Element“. Offensichtlich hat Ihr iec Objekt nicht implementiert IList und nur implementiert IEnumerable , so dass es unmöglich ist, ein zufälliger zu tun lesen (ohne natürlich eine Erweiterungsmethode oder etwas, das den Enumerator verwendet den Zufallsindex zu erreichen). Zukunfts nur die einzige verfügbare Option ist zu lesen.

Die am demontierten Code für die ElementAt Methode aussehen lassen. Klar, wenn die Quellensammlung nicht IList implementieren, rufen wir den aktuellen Eintrag im enumerator:

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
{
    TSource current;
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    IList<TSource> list = source as IList<TSource>;
    if (list != null)
    {
        return list[index];
    }
    if (index < 0)
    {
        throw Error.ArgumentOutOfRange("index");
    }
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
    Label_0036:
        if (!enumerator.MoveNext())
        {
            throw Error.ArgumentOutOfRange("index");
        }
        if (index == 0)
        {
            current = enumerator.Current;
        }
        else
        {
            index--;
            goto Label_0036;
        }
    }
    return current;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top