【发布时间】:2016-05-31 14:33:22
【问题描述】:
根据MS documentation,如果底层枚举源被修改,枚举器应该抛出 InvalidOperationEx。当我直接从 IEnumerable 获取枚举器时,这很有效。
问题:但是如果我从“查询数据结构”获取枚举器,然后修改源然后调用 MoveNext(),则不会抛出任何内容(参见代码)。
考虑以下代码:
public static void Main(string[] args)
{
var src = new List<int>() { 1, 2, 3, 4 };
var q = src.Where(i => i % 2 == 1);
IEnumerable<int> nl = src;
var enmLinq = q.GetEnumerator();
var enmNonLinq = nl.GetEnumerator();
src.Add(5); //both enumerators should be invalid, as underlying data source changed
try
{
//throws as expected
enmNonLinq.MoveNext();
}
catch (InvalidOperationException)
{
Console.WriteLine("non LINQ enumerator threw...");
}
try
{
//DOES NOT throw as expected
enmLinq.MoveNext();
}
catch (InvalidOperationException)
{
Console.WriteLine("enumerator from LINQ threw...");
}
//It seems that if we want enmLinq to throw exception as expected:
//we must at least once call MoveNext on it (before modification)
enmLinq.MoveNext();
src.Add(6);
enmLinq.MoveNext(); // now it throws as it should
}
看来你必须先调用MoveNext()方法让它注意到底层源的变化。
为什么我认为会发生这种情况: 我认为这是因为“查询结构”给了你太懒惰的枚举器,而不是在 GetEnumerator() 上初始化,而是在第一次调用 MoveNext() 时初始化。
初始化是指将所有枚举器(从 WhereEnumerable、SelectEnumerable 等 LINQ 方法返回的结构)连接到真正的底层数据结构。
问题: 我是对的还是我错过了什么? 您认为这是奇怪/错误的行为吗?
【问题讨论】: