Yield是如何实现延迟加载模式的?
yield
是如何实现延迟加载
模式的?
How yield
implements the pattern of lazy loading
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
yield
是如何实现延迟加载
模式的?
How yield
implements the pattern of lazy loading
?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(3)
在需要时,yield 实现不会到达代码。
例如,以下代码:
实际上会编译为实现 IEnumerable的嵌套类,并且
GetInts()
的主体将返回该类的实例。使用反射器,您可以看到:
编辑 - 添加有关
GetInts
实现的更多信息:此实现使其变得懒惰的方式基于
Enumerator
MoveNext()
方法。当生成可枚举嵌套类时(示例中的d__6d
),它具有一个状态,并且每个状态都连接一个值(这是一个简单的情况,在更高级的情况下,该值当代码达到该状态时将被评估)。如果我们查看d__6d
的MoveNext()
代码,我们将看到以下状态:当向枚举器请求当前对象时,它返回连接到当前状态的对象。
为了表明代码仅在需要时才被评估,您可以查看这个示例:
我希望它更清晰一些。我建议使用 Reflector 查看代码,并在更改“yield”代码时观察编译后的代码。
yield implementation doesn't reach the code until it's needed.
For example, this code:
Will actually compile into a nested class which implements
IEnumerable<int>
and the body ofGetInts()
will return an instance of that class.Using reflector you can see:
Edit - adding more info about
GetInts
implementation:The way this implementation makes it lazy is based on the
Enumerator
MoveNext()
method. When the enumerable nested class is generated (<GetInts>d__6d
in the example), it has a state and to each state a value is connected (this is a simple case, in more advanced cases the value will be evaluated when the code reach the state). If we take a look in theMoveNext()
code of<GetInts>d__6d
we'll see the state:When the enumerator is asked for the current object it returns the object which is connected to the current state.
In order to show that the code is evaluated only when it's required you can look at this example:
I hope it's a bit more clear. I recommend to take a look at the code with Reflector and observe the compiled code as you change the "yield" code.
如果您想了解有关编译器在使用
yield return
时执行的操作的更多信息,请查看 Jon Skeet 撰写的这篇文章:迭代器块实现细节If you want to know more about what the compiler is doing when using
yield return
, check this article by Jon Skeet: Iterator block implementation details基本上,使用
yield
语句实现的迭代器被编译成一个实现 状态机的类。如果您从未
foreach
(=迭代并实际使用)返回的IEnumerable
,则该代码永远不会实际执行。如果这样做,则仅执行确定要返回的下一个值所需的最少代码,仅在请求下一个值时恢复执行。当您在调试器中单步执行此类代码时,您实际上可以看到这种行为发生。至少尝试一次:我认为看到这一步步发生是很有启发的。
Basically iterators implementated by using
yield
statements are compiled into a class that implements a state machine.If you never
foreach
(=iterate over and actually use) the returnedIEnumerable<T>
, the code is never actually executed. And if you do, only the minimal code needed to determine the next value to return is executed, only to resume execution when a next value is requested.You can actually see this behavior happening when you single step such code in the debugger. Try it at least once: I think it's illuminating to see this happen step by step.