1

谁能告诉我为什么下面的代码不能按我期望的方式工作?我正在尝试围绕 StreamReader 编写一个 IEnumberable 包装器,但是当我在其上使用 ElementAt 时,它会从流中读取顺序字符,而不管我传递给 ElementAt 的索引如何。

文件“test.txt”包含“abcdefghijklmnopqrstuvwxyz”。我希望输出是:

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 啊啊
啊啊

相反,我得到

abcdefghijklmnopqrstuvwxyz

并且 ArgumentOutOfRangeException 被调用,即使到目前为止我传递给 ElementAt 的唯一索引是 0。

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 回答