1

次のコードが期待どおりに機能しない理由を誰かに教えてもらえますか?StreamReaderの周りにIEnumberableラッパーを書き込もうとしていますが、ElementAtを使用すると、ElementAtに渡すインデックスに関係なく、ストリームから連続した文字が読み取られます。

ファイル「test.txt」には「abcdefghijklmnopqrstuvwxyz」が含まれています。出力は次のようになると思います。

aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbb ..。
_

代わりに私は得る

abcdefghijklmnopqrstuvwxyz

これまでにElementAtに渡したインデックスは0だけですが、ArgumentOutOfRangeExceptionが呼び出されます。

MSDNによると:

ソースのタイプがIList<(Of <(T>)>)を実装している場合、その実装は、指定されたインデックスの要素を取得するために使用されます。それ以外の場合、このメソッドは指定された要素を取得します。

それは「次の要素を取得する」と読むべきですか?もしそうなら、それはちょっと怠惰なリストの目的を打ち負かします...

    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();
            }
        }
    }
4

1 に答える 1

1

はい、MSDNのドキュメントには「次の要素を取得する」と記載されているはずです。明らかに、iecオブジェクトはIListを実装せず、 IEnumerableのみを実装するため、ランダム読み取りを実行することはできません(もちろん、拡張メソッドまたは列挙子を使用してランダムインデックスに到達するものがなければ)。前方のみの読み取りが唯一の利用可能なオプションです。

ElementAtメソッドの逆アセンブルされたコードを見てみましょう。明らかに、ソースコレクションがIListを実装していない場合、列挙子で現在のアイテムを取得します。

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;
}
于 2009-03-28T00:24:41.803 に答える