The yield
keyword actually does quite a lot here.
(yield
关键字实际上在这里做了很多工作。)
The function returns an object that implements the IEnumerable<object>
interface.
(该函数返回一个实现IEnumerable<object>
接口的IEnumerable<object>
。)
If a calling function starts foreach
ing over this object, the function is called again until it "yields". (如果调用函数开始foreach
此对象,则会再次调用该函数,直到“屈服”为止。)
This is syntactic sugar introduced in C# 2.0 . (这是C#2.0中引入的语法糖。)
In earlier versions you had to create your own IEnumerable
and IEnumerator
objects to do stuff like this. (在早期版本中,您必须创建自己的IEnumerable
和IEnumerator
对象才能执行此类操作。)
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;
}
When you step through the example, you'll find the first call to Integers()
returns 1
.
(在逐步浏览示例时,您会发现对Integers()
的第一次调用返回1
。)
The second call returns 2
and the line yield return 1
is not executed again. (第二次调用返回2
,并且行yield return 1
不再执行。)
Here is a real-life example:
(这是一个真实的例子:)
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);
}
}
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…