gpt4 book ai didi

c# - 生成器方法在多次枚举期间被调用两次

转载 作者:行者123 更新时间:2023-11-30 16:43:31 25 4
gpt4 key购买 nike

我试图理解为什么下面的代码会这样运行:

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication
{
internal class Program
{
private static IEnumerable<int> Foo()
{
Console.WriteLine("Hello world!");
for (var i = 0; i < 10; i++)
yield return i;
}

public static void Main(string[] args)
{
var x = Foo();

var y = x.Take(3);
foreach (var i in y)
Console.WriteLine(i);

var z = x.Skip(3);
foreach (var i in z)
Console.WriteLine(i);
}
}
}

在 main 中,我得到一个名为 x 的新“生成器”(请原谅 python 术语),然后我尝试枚举它两次。我第一次获取前 3 个元素并打印它们:我希望程序打印“Hello world!”然后是从 0 到 2 的数字。第二次我采用相同的可枚举并跳过 3 个以上的元素。我希望程序打印 6 到 9 的数字,而不打印“Hello world!”首先。

相反,程序第二次打印“Hello world!”第二次,然后从 3 开始枚举,直到 9。

我不明白:为什么 Foo() 被调用了两次?

EDIT1:不是重复的。链接的“重复”询问编写可枚举时的最佳实践,在这里我无法使用它的值。

EDIT2:我接受了一个老实说不是很好的答案,但包含一个指向使我理解问题的引用的链接。令我困惑的是 foreach 循环在遍历 IEnumerable 时实际上是如何工作的,因此我将在此处进行解释以供将来引用。

IEnumerable 是值的序列 - 底层实现是无关紧要的,只要它是可以按顺序为您提供值的东西即可。当您在其上使用 foreach 循环时,它会创建一个 Enumerator 对象,该对象基本上是一个游标,用于跟踪循环到达的位置。

所以发生的事情是第一个循环创建了第一个枚举器,它又必须启动我的生成器方法并打印第一个字符串。

第二个循环无法获取前一个枚举器(正如我所相信的那样)。相反,它实例化了第二个枚举器,后者又重新启动生成器,从而打印第二个字符串。

对于任何阅读本文的 pythonista,请注意它与生成器在 python 中的工作方式截然相反(重用可迭代对象不会重新启动它)。

最佳答案

在 C# 中,当您使用 yield返回 IEnumerable 的方法或属性中的关键字或 IEnumerable<T>该方法(或属性)成为一个惰性序列,它不只是返回一个列表或类似数组的结构,它运行该方法直到第一个 yield语句,然后暂停,直到从调用代码(您的 Main 方法)中“拉出”下一个元素。

所以当你写x = Foo()你正在设置 x等于执行 Foo 主体的惰性序列每次你循环它。 Foo 对 body 的任何副作用将在该状态机的每次迭代中执行一次。

SkipTake每个都以惰性序列作为输入,然后是yield return根据需要添加元素,从而产生一个新的惰性序列。所以当你写 y = x.Take(3) , 那里没有迭代,但是当你 foreach y , 它将有效地执行 Foo直到第三个yield声明。

Skip源代码: https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Skip.cs

同样z = x.Skip(3)使 z第三个惰性序列,通过组合 x 创建与 Skip手术。此处不会立即迭代任何内容,但当您 foreach z , 它将执行 Foo 的整个主体,但会“丢弃”前 3 个元素。

参见 Jon Skeet 的书:http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

关于c# - 生成器方法在多次枚举期间被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44847342/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com