任何人都可以告诉我为什么下面的代码不能按照我的预期工作吗?我正在尝试围绕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();
}
}
}
答案 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;
}