我正在进行一项运行验证方法的简单测试,并遇到了这种奇怪的情况。
public IEnumerable<int> ints (List<int> l)
{
if(false)yield return 6;
l.Add(4);
}
void Main()
{
var a = new List<int>();
var b = new List<int>();
for( int i = 0; i < 4; i++ ){
a.Add(i);
b.Add(i);
}
a.AddRange(ints(a));
ints(b);
Console.WriteLine(a);
Console.WriteLine(b);
}
此代码运行后,a
将包含[0,1,2,3,4]
。但是,b
将包含[0,1,2,3]
。为什么在AddRange
中将方法作为参数调用允许列表通过引用传递?或者,如果没有发生,那做了什么?
答案 0 :(得分:15)
ints(b)
调用不会枚举IEnumerable
,因此代码永远不会到达l.Add(4)
行,这与AddRange
枚举所有项目以将其添加到列表中的情况不同。
要查看它,请手动调用b
案例枚举结果:
ints(b).ToList();
通过函数实现的 IEnumerable<T>
在枚举开始之前不执行函数体 - 代码实际上由编译器转换为具有状态的类,以支持可枚举的真正延迟评估(详细信息可以在多篇文章中找到,即Iterator Pattern demystified - Tim Schmelter提供的链接。)