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

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

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


当前回答

这是一个非常简单和容易的方法来创建一个枚举对象。编译器创建了一个类来包装您的方法,并在本例中实现IEnumerable<object>。如果没有yield关键字,则必须创建一个实现IEnumerable<object>的对象。

其他回答

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

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

乍一看,yield return是一个。net糖返回一个IEnumerable。

如果没有yield,集合中的所有项都是一次性创建的:

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        return new List<SomeData> {
            new SomeData(), 
            new SomeData(), 
            new SomeData()
        };
    }
}

同样的代码使用yield,它逐项返回:

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        yield return new SomeData();
        yield return new SomeData();
        yield return new SomeData();
    }
}

使用yield的优点是,如果使用数据的函数只需要集合的第一个项,则不会创建其余的项。

yield操作符允许根据需要创建项。这是一个使用它的好理由。

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

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

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

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

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