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

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

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


当前回答

下面是理解这个概念的简单方法: 其基本思想是,如果您想要一个可以使用“foreach”的集合,但是由于某些原因将项收集到集合中成本很高(例如从数据库中查询它们),并且通常不需要整个集合,那么您可以创建一个函数,每次构建一个项集合并将其返回给消费者(然后消费者可以提前终止收集工作)。

Think of it this way: You go to the meat counter and want to buy a pound of sliced ham. The butcher takes a 10-pound ham to the back, puts it on the slicer machine, slices the whole thing, then brings the pile of slices back to you and measures out a pound of it. (OLD way). With yield, the butcher brings the slicer machine to the counter, and starts slicing and "yielding" each slice onto the scale until it measures 1-pound, then wraps it for you and you're done. The Old Way may be better for the butcher (lets him organize his machinery the way he likes), but the New Way is clearly more efficient in most cases for the consumer.

其他回答

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

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

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

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

关于Yield关键字的一个主要观点是惰性执行。现在我所说的惰性执行是指在需要时执行。更好的表达方式是举个例子

示例:不使用Yield,即没有Lazy Execution。

public static IEnumerable<int> CreateCollectionWithList()
{
    var list =  new List<int>();
    list.Add(10);
    list.Add(0);
    list.Add(1);
    list.Add(2);
    list.Add(20);

    return list;
}

示例:使用Yield,即惰性执行。

public static IEnumerable<int> CreateCollectionWithYield()
{
    yield return 10;
    for (int i = 0; i < 3; i++) 
    {
        yield return i;
    }

    yield return 20;
}

当我调用两个方法时。

var listItems = CreateCollectionWithList();
var yieldedItems = CreateCollectionWithYield();

你会注意到listItems里面有5个项目(调试时将鼠标悬停在listItems上)。 而yieldItems将只有一个对方法的引用,而不是对项目的引用。 这意味着它没有在方法中执行获取项的过程。一种只在需要时获取数据的非常有效的方法。 yield的实际实现可以在ORM中看到,如Entity Framework和NHibernate等。

迭代。它创建了一个“隐藏的”状态机,它会记住您在函数的每个额外循环中的位置,并从那里开始处理。

屈服有两大用处,

它有助于在不创建临时集合的情况下提供自定义迭代。 它有助于进行有状态迭代。

为了更清楚地解释以上两点,我制作了一个简单的视频,你可以在这里观看