C#3.0 ElementAt是否因迭代器函数而被破坏?

时间:2009-03-28 00:21:28

标签: c# linq streamreader

任何人都可以告诉我为什么下面的代码不能按照我的预期工作吗?我正在尝试围绕StreamReader编写IEnumberable包装器,但是当我在其上使用ElementAt时,无论我传递给ElementAt的索引如何,它都会从流中读取连续字符。

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

  

aaaaaaaaaaaaaaaaaaaaaaaaaaa
  bbbbbbbbbbbbbbbbbbbbbbbbbbb
  ...

相反,我得到

  

ABCDEFGHIJKLMNOPQRSTUVWXYZ

调用

和ArgumentOutOfRangeException,即使我到目前为止传递给ElementAt的唯一索引是0。

MSDN说:

  

如果源的类型实现IList<(Of<(T>)>),则该实现用于获取指定索引处的元素。否则,此方法获取指定的元素。

是否应该“获取 next 元素”?如果是这样的话,那就失去了懒惰名单的目的......

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

1 个答案:

答案 0 :(得分: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;
}