有人可以解释一下这个懒惰的评估代码吗?所以,刚刚问了这个问题:Howtodealwith"infinite"IEnumerable?我的示例代码:publicstaticvoidMain(string[]args){foreach(variteminNumbers().Take(10))Console.WriteLine(item);控制台.ReadKey();}publicstaticIEnumerableNumbers(){intx=0;while(true)yieldreturnx++;有人可以解释为什么这是惰性评估吗?我在Reflector中查看了这段代码,我比开始时更加困惑。反射器输出:publicstaticIEnumerableNumbers(){returnnewd__0(-2);对于numbers方法,它看起来像是为表达式生成了一个新类型:[DebuggerHidden]publicd__0(int1__state){this.1__state=1__state;this.l__initialThreadId=Thread.CurrentThread.ManagedThreadId;这对我来说没有意义。在我将代码放在一起并自己完成之前,我会认为这是一个无限循环。编辑:所以我现在明白了.Take()可以告诉foreach枚举实际上还没有完成,但是不应该在它被完全调用之前调用它(而不是链接到Take()?结果是实际枚举的结果,对吗?但是如果数字没有被完全评估,它是如何强制执行的?EDIT2:这只是“yield”关键字强制执行的特定编译器技巧吗?这不是无限循环的原因是根据Linq的Take(10)调用,您只使用了枚举10次。现在,如果您编写如下代码:foreach(variteminNumbers()){}现在这是一个无限循环,因为您的枚举器将始终返回一个新值。C#编译器采用此代码并将其转换为状态机。如果您的枚举器没有保护子句来中断执行,那么调用者必须在您的示例中执行此操作。代码惰性的原因也是代码工作的原因。基本上Take返回第一个项目,然后你的应用程序消耗,然后它需要另一个直到它已经拿了10个项目。编辑这实际上与添加take无关。这些被称为迭代器。C#编译器对您的代码执行复杂的转换,从您的方法创建枚举器。我建议阅读,但基本上(这可能不是100%准确),您的代码将进入Numbers方法,您可以在其中启动状态机。一旦您的代码遇到yieldreturn,您实际上是在说Numbers()停止执行并返回此结果,然后当他们要求下一项恢复执行时,在yieldreturn之后的下一行。ErikLippert在迭代器的杂项方面有很多系列这与以下内容有关:当您枚举任何类型的IEnumerable时,该类会为您提供它将为您提供的下一个项目。它不会对其所有项目执行任何操作,它只会为您提供下一个项目。它决定了该项目将是什么。(例如,有些集合是有序的,有些不是。有些不保证特定的顺序,但似乎总是按照您放入它们的顺序给它们。)。IEnumerable扩展方法Take()将枚举10次并获取前10项。你可以做Take(100000000),它会给你那么多数字。但你只是在做Take(10)。它只是向Numbers()询问下一项。..10倍。对于这10个项目中的每一个,Numbers给出了下一个项目。要了解如何,您需要阅读Yield声明。它是更复杂的东西的语法糖。产量非常强劲。(我是一名VB开发人员,很生气我仍然没有。)它不是函数;它是函数。这是一个有一定限制的关键字。它使定义枚举器比其他方式更容易。其他IEnumerable扩展方法始终迭代每个项目。调用.AsList会把它炸毁。使用它,大多数LINQ查询都会搞砸。基本上,您的Numbers()函数会创建一个枚举器。foreach将在每次迭代中检查枚举器是否已到达末尾,如果没有,将继续。您的特定囚犯永远不会结束,但这并不重要。这是惰性评估。枚举器将生成??“实时”结果。这意味着如果你要写。把(3)放在那里,循环只会执行三次。枚举器仍会在其中“留下”一些项目,但由于当前没有方法需要它们,因此不会生成它们。如果您尝试像函数暗示的那样生成从0到无穷大的所有数字,并一次返回所有数字,则只使用其中10个的程序会慢得多。这就是惰性评估的好处——从未使用过的东西永远不会被计算。C#学习教程就这些了:有人可以解释一下这个懒惰的求值代码吗?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
