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

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

问题描述:

如何只公开IList的一个片段<> 问题之一的答案有以下代码片段:

In the How Can I Expose Only a Fragment of IList<> question one of the answers had the following code snippet:

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

yield 关键字在那里有什么作用?我已经在几个地方和另一个问题中看到了它的引用,但我还没有完全弄清楚它的实际作用.我习惯于从一个线程屈服于另一个线程的意义上考虑屈服,但这在这里似乎并不相关.

What does the yield keyword do there? I've seen it referenced in a couple places, and one other question, but I haven't quite figured out what it actually does. I'm used to thinking of yield in the sense of one thread yielding to another, but that doesn't seem relevant here.

yield 上下文关键字实际上在这里做了很多.

The yield contextual keyword actually does quite a lot here.

该函数返回一个实现 IEnumerable 接口的对象.如果调用函数开始对这个对象进行foreach,则该函数将再次被调用,直到它产生".这是C# 2.0 中引入的语法糖.在早期版本中,您必须创建自己的 IEnumerableIEnumerator 对象才能执行此类操作.

The function returns an object that implements the IEnumerable<object> interface. If a calling function starts foreaching over this object, the function is called again until it "yields". This is syntactic sugar introduced in C# 2.0. In earlier versions you had to create your own IEnumerable and IEnumerator objects to do stuff like this.

理解这样的代码最简单的方法是输入一个例子,设置一些断点,看看会发生什么.尝试逐步完成此示例:

The easiest way understand code like this is to type-in an example, set some breakpoints and see what happens. Try stepping through this example:

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 不再执行.

When you step through the example, you'll find the first call to Integers() returns 1. The second call returns 2 and the line yield return 1 is not executed again.

这是一个真实的例子:

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);
                }
            }
        }
    }
}