即使用了yield return,为什么count还是1000000?
来源:12-8 【操作】迭代与 yield return

2227181
2023-05-24
static IEnumerable<Customer> GetCustomersYield(int count)
{
for (int i = 0; i < count; i++)
{
yield return new Customer(i, $"阿莱克斯{i}", "广州");
if (i > 3)
{
yield break;
}
}
老师,对于课上GetCustomersYield()这个例子,既然yield return实现了用时再加载,为什么第一加载后,返回的customers里的count就是1000000了?C#编译器在预处理阶段根据代码做了简单的推断?
为了证实这个猜想,我添加了“yield break;”的代码,也就是实际只能迭代0~4共5次。但是count仍然是1000000。看来预处理并没有处理/理解我加的代码。
请教下这个count变为1000000的原理是什么呢?谢谢。
1回答
-
阿莱克斯刘
2023-06-01
这个问题问的很好,在第一次执行GetCustomersYield方法的时候,customer列表其实就已经产生了,编译器会自动拾取yield return出现的次数。而yield return出现多少次那么customer列表就会有多长。
比如,在下面的这个例子中,yield return出现了多少次?三次对吧?那么这个CreateEnumerable()方法就会产生一个拥有三个元素的列表。但是,请注意,在我们真正访问CreateEnumerable列表的之前,这个列表所包含的数据只是一个占位,你可以把它理解为[x,x,x]。只有当我们真正使用到这个列表中某个数据的时候,数据才会被加载到列表中。比如说,CreateEnumerable列表创建好以后,当我需要访问第一个元素的时候,列表会变成[1,x,x];当我想访问第二个的时候,列表会变成[1,2,x]。也就是说只有在我们真正需要使用到这个列表中的数据的时候,数据才被加载进列表。
同样的道理,GetCustomersYield方法中有一个需要执行100万次的for循环,也就是说这个方法中实际上拥有100万个yield return。所以,这就是为什么GetCustomersYield明明只运行了3次,却产生了一个100万长度的列表。
需要注意的是,yield return所产生的列表的长度只与它“出现”的次数有关,与执行次数无关。也就是说即使不执行yield return,只要你代码里写了yield return也会产生相应数量长度的列表,只不过列表中每个元素的数据都是暂时没有占用内存空间的。
还需要注意的是,通过yield return所产生的列表是高度抽象的,根据c#的定义,它与普通列表在使用上没有任何区别。所以,无论GetCustomersYield中的for循环执行多少次,GetCustomersYield所产生的列表在使用体验上应该是与GetCustomers所产生的列表完全没有区别才对,所以,虽然GetCustomersYield只执行了三次,但是它与GetCustomers所产生的列表长度必须是一样的才对,只是GetCustomersYield产生的绝大部分元素都不消耗内存而已。内存消耗少,这也是为什么yield return如此高效的原因之一。
012023-06-01
相似问题