2

首先,我已经对此进行了搜索,但我仍然无法理解何时使用 yield。

例如,我有以下代码:

string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

public System.Collections.IEnumerator GetEnumerator()
{
    for (int i = 0; i < days.Length; i++)
    {
        yield return days[i];
    }
}

上面的代码和下面的代码有什么区别?

string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

public System.Collections.IEnumerator GetEnumerator()
{
    for (int i = 0; i < days.Length; i++)
    {
        return days[i];
    }
}

你能告诉我什么时候使用yield吗?

4

3 回答 3

10

return方法不记得您在数组中的位置。每次使用它时它都会返回星期日,这仅仅是因为它每次都从零开始循环。

使用yield更多(至少在概念上)“我会返回这个值,但是下次你打电话给我时,我会从我离开的地方继续(在循环内)”。

类似的事情可以在 C 中使用静态变量来记住你在哪里:

char *nextDay () {
    static char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
    static int nextDay = -1;
    nextDay = (nextDay + 1) % (sizeof (days) / sizeof (*days));
    return days[nextDay];
}

变量在函数的调用中被维护的事实nextDay意味着它可以用来循环遍历数组。

于 2012-06-15T00:40:25.480 回答
4

C# 中的某些结构会导致编译器将代码转换成非常不同的东西。该yield return声明导致了这种转变。看起来像执行 a 的函数yield return实际上被编译成一个类;函数中的许多局部变量都被转换为类字段。类本身通常会实现IEnumerable<T>IEnumerator<T>。第一次MoveNext调用时,类代码将运行函数的部分直到第一次yield return,并跟踪yield return它命中的部分。下次调用它时,它将在那里开始执行并运行直到下一次yield return被调用。如果有任何Try/Finally块,块中的代码部分Finally将响应IDisposable.Dispose.

最终效果是 C# 编译器为迭代器生成的代码看起来几乎与程序员编写的代码完全不同。看起来yield return不可能的原因是它的行为对于任何类似于方法调用的东西都是不可能的,但是编译器将任何包含 a 的函数yield return转换为一个其行为甚至与方法调用都不相似的类。

于 2012-06-15T00:59:55.517 回答
0

Yield 与 foreach 循环和 for 循环交互。它允许仅在需要时生成 foreach 循环或 for 循环中的每次迭代。这样可以提高性能。

可以在此处找到有关产量及其好处的完整说明:

http://www.ytechie.com/2009/02/using-c-yield-for-readability-and-performance.html

于 2012-06-15T00:42:10.610 回答