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ステートメントはそのような変換を引き起こします。を実行する関数のように見えるものは、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 に答える