根据MS documentation,枚举器应该抛出InvalidOperationEx,如果底层的枚举源被修改。这工作时,我直接从IEnumerable获得枚举数。但是,如果我从“查询数据结构”获取枚举数,然后修改源并调用MoveNext(),则不会引发任何操作(请参阅代码)。LINQ中枚举器的怪异行为
考虑下面的代码:
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方法返回的结构),直到真正的底层数据结构。
问题: 我说得对吗?或者我错过了什么? 你认为这是奇怪/错误的行为?
谢谢你,你认为它是MS实施中的错误/不一致吗? – videokojot
@videokojot我会说这是由设计。 LINQ通常尽可能延迟,直到这一点,它不需要源枚举器(例如,您可能永远不会枚举查询)。 –
好的,谢谢。公认。尽管如此,我觉得有点奇怪,但生病了。 – videokojot