协慌网

登录 贡献 社区

C#中使用的 yield 关键字是什么?

在 “ 我如何仅公开 IList 的片段 <>问题” 中,其中一个答案包含以下代码段:

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

yield 关键字有什么作用?我已经看到它在几个地方被引用,另外一个问题,但我还没弄清楚它实际上做了什么。我习惯于在一个线程产生另一个线程的意义上考虑收益率,但这似乎并不重要。

答案

yield 关键字实际上在这里做了很多。该函数返回一个实现 IEnumerable 接口的对象。如果一个调用函数开始对该对象进行预处理,则再次调用该函数,直到它 “产生” 为止。这是 C#2.0 中引入的语法糖。在早期版本中,您必须创建自己的 IEnumerable 和 IEnumerator 对象来执行此类操作。

理解这样的代码的最简单方法是键入一个示例,设置一些断点并查看会发生什么。

尝试单步执行此操作,例如:

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

当您单步执行该示例时,您将发现对 Integers()的第一次调用返回 1. 第二次调用返回 2 并且不再执行 “yield return 1” 行。

这是一个现实生活中的例子

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
{
    using (var connection = CreateConnection())
    {
        using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
        {
            command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return make(reader);
                }
            }
        }
    }
}

迭代。它创建了一个 “幕后” 的状态机,可以记住你在函数的每个附加周期中的位置并从中获取。

产量有两大用途,

  1. 它有助于提供自定义迭代而无需创建临时集合。

  2. 它有助于进行有状态迭代。 在此输入图像描述

为了更具说明性地解释上述两点,我创建了一个简单的视频,你可以在这里观看