在如何只能暴露IList<>的一个片段问题中,其中一个答案有以下代码片段:

IEnumerable<object> FilteredList()
{
    foreach(object item in FullList)
    {
        if(IsItemInPartialList(item))
            yield return item;
    }
}

yield关键字在这里做什么?我在一些地方看到过它,还有一个问题,但我还没搞清楚它到底是干什么的。我习惯于从一个线程屈服于另一个线程的意义上考虑屈服,但这在这里似乎无关紧要。


当前回答

Yield return与枚举器一起使用。在yield语句的每次调用中,控制权都返回给调用方,但它确保被调用方的状态得到维护。因此,当调用方枚举下一个元素时,它将在yield语句之后立即在被调用方方法from语句中继续执行。

让我们通过一个例子来理解这一点。在这个例子中,对应于每一行,我已经提到了执行流的顺序。

static void Main(string[] args)
{
    foreach (int fib in Fibs(6))//1, 5
    {
        Console.WriteLine(fib + " ");//4, 10
    }            
}

static IEnumerable<int> Fibs(int fibCount)
{
    for (int i = 0, prevFib = 0, currFib = 1; i < fibCount; i++)//2
    {
        yield return prevFib;//3, 9
        int newFib = prevFib + currFib;//6
        prevFib = currFib;//7
        currFib = newFib;//8
    }
}

此外,还为每个枚举维护状态。假设,我对Fibs()方法有另一个调用,那么它的状态将被重置。

其他回答

直观地,关键字从函数中返回一个值而不离开它,即在您的代码示例中,它返回当前项的值,然后继续循环。更正式地说,它被编译器用来为迭代器生成代码。迭代器是返回IEnumerable对象的函数。MSDN上有几篇关于它们的文章。

如果我正确地理解了这一点,下面是我如何从函数实现IEnumerable的角度来表达这一点。

这是一个。 如果你需要另一个,请再打电话。 我会记得我给你的。 你下次打电话来的时候我才知道能不能再给你。

c#的yield关键字,简单地说,允许多次调用一段被称为迭代器的代码,它知道如何在完成之前返回,并且当再次调用时,继续它离开的地方——也就是说,它帮助迭代器在连续调用中返回的序列中的每一项都具有透明的状态。

在JavaScript中,同样的概念被称为生成器。

它产生了可枚举的序列。它所做的实际上是创建本地IEnumerable序列,并将其作为方法结果返回

最近Raymond Chen也发表了一系列关于yield关键字的有趣文章。

c#中迭代器的实现及其后果(第1部分) c#中迭代器的实现及其后果(第2部分) c#中迭代器的实现及其后果(第3部分) c#中迭代器的实现及其后果(第4部分)

虽然它名义上用于轻松实现迭代器模式,但可以泛化为状态机。没有必要引用Raymond,最后一部分也链接到其他用法(但Entin博客中的例子特别好,展示了如何编写异步安全代码)。