请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

即使用了yield return,为什么count还是1000000?

    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的原理是什么呢?谢谢。

正在回答 回答被采纳积分+3

1回答

阿莱克斯刘 2023-06-01 02:43:47

这个问题问的很好,在第一次执行GetCustomersYield方法的时候,customer列表其实就已经产生了,编译器会自动拾取yield return出现的次数。而yield return出现多少次那么customer列表就会有多长。


  • 比如,在下面的这个例子中,yield return出现了多少次?三次对吧?那么这个CreateEnumerable()方法就会产生一个拥有三个元素的列表。但是,请注意,在我们真正访问CreateEnumerable列表的之前,这个列表所包含的数据只是一个占位,你可以把它理解为[x,x,x]。只有当我们真正使用到这个列表中某个数据的时候,数据才会被加载到列表中。比如说,CreateEnumerable列表创建好以后,当我需要访问第一个元素的时候,列表会变成[1,x,x];当我想访问第二个的时候,列表会变成[1,2,x]。也就是说只有在我们真正需要使用到这个列表中的数据的时候,数据才被加载进列表。

https://img1.sycdn.imooc.com//szimg/64779285098dfddc04960126.jpg

  • 同样的道理,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如此高效的原因之一。

0 回复 有任何疑惑可以回复我~
  • 提问者 2227181 #1
    谢谢老师细致的答复。看来预处理器会将循环展开从而得到100万的出现数量,但是不会去推测其中的逻辑分支代码,这确实是合理的。不过既然它把Count赋成了100万,如果外边的代码直接访问第100万个数据或者从100万开始往前循环,不知道yied return会如何执行?可以试试,应该挺有趣。
    回复 有任何疑惑可以回复我~ 2023-06-01 09:24:18
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信