Question

Quelqu'un peut-il me dire pourquoi le code suivant ne fonctionne pas comme j'attends? Je suis en train d'écrire une enveloppe IEnumberable autour d'un StreamReader, mais quand je l'utilise ElementAt dessus, il lit des caractères consécutifs à partir du flux quel que soit l'indice que je passe à ElementAt.

Le fichier "test.txt" contient "abcdefghijklmnopqrstuvwxyz". Je pense que la sortie soit:

  

aaaaaaaaaaaaaaaaaaaaaaaaaaa
  bbbbbbbbbbbbbbbbbbbbbbbbbbb
  ...

Au lieu de cela, je reçois

  

abcdefghijklmnopqrstuvwxyz

et ArgumentOutOfRangeException est appelée, même si le seul indice que je l'ai passé à ElementAt jusqu'à présent est 0.

MSDN dit:

  

Si le type de source implémente IList <(Of <(T>)>), que la mise en œuvre est utilisée pour obtenir l'élément à l'index spécifié. Dans le cas contraire, cette méthode obtient l'élément spécifié.

Si on pouvait lire "obtient le suivant élément"? Si oui, que des défaites un peu le but des listes paresseux ...

    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();
            }
        }
    }
Était-ce utile?

La solution

Oui, la documentation MSDN devrait lire « obtient l'élément suivant ». Il est évident que votre objet iec ne met pas en œuvre IList et uniquement IEnumerable, il est donc impossible de faire un hasard lire (sans bien sûr une méthode d'extension ou quelque chose qui utilise le recenseur pour atteindre l'indice aléatoire). Forward lecture seule est la seule option disponible.

Regardons le code désassemblé pour la méthode ElementAt. Il est clair que, si la collecte source ne met pas en œuvre IList, nous récupérons l'élément en cours dans le recenseur:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top