为什么使用yield关键字时,我只能使用普通的IEnumerable?

鉴于此代码:

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

为什么我不应该这样编码?:

IEnumerable<object> FilteredList()
{
    var list = new List<object>(); 
    foreach( object item in FullList )
    {
        if( IsItemInPartialList( item ) )
            list.Add(item);
    }
    return list;
}

我有点理解yield关键字的作用。 它告诉编译器构建某种类型的东西(一个迭代器)。 但为什么使用它? 除了少一点代码之外,它对我有什么作用?


使用yield会使收藏懒惰。

假设你只需要前五项。 按照你的方式,我必须遍历整个列表以获得前五项。 有了yield ,我只能循环前五项。


迭代器块的好处是它们懒惰地工作。 所以你可以写这样的过滤方法:

public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
                                   Func<T, bool> predicate)
{
    foreach (var item in source)
    {
        if (predicate(item))
        {
            yield return item;
        }
    }
}

这将允许你只要你喜欢就过滤一个流,从不缓冲多于一个单一的项目。 例如,如果您只需要返回序列中的第一个值,那么您为什么要将所有内容都复制到新列表中?

作为另一个例子,您可以使用迭代器块轻松创建无限流。 例如,下面是一系列随机数字:

public static IEnumerable<int> RandomSequence(int minInclusive, int maxExclusive)
{
    Random rng = new Random();
    while (true)
    {
        yield return rng.Next(minInclusive, maxExclusive);
    }
}

你将如何在列表中存储无限序列?

我的Edulinq博客系列给出了大量使用迭代器块的LINQ to Objects的示例实现。 LINQ从根本上来说是懒惰的 - 把事情放在一个列表中根本不会那样工作。


使用“列表”代码,您必须先处理完整列表,然后才能将其传递到下一步。 “yield”版本立即将处理后的项目传递给下一步。 如果该“下一步”包含“.Take(10)”,那么“收益”版本将只处理前10个项目并忘记其余的项目。 “列表”代码将处理所有内容。

这意味着当您需要进行大量处理和/或需要处理大量项目列表时,您会发现最大的不同。

链接地址: http://www.djcxy.com/p/9101.html

上一篇: Why use the yield keyword, when I could just use an ordinary IEnumerable?

下一篇: Is there a goto statement in Java?