22

次のコードをステップ実行すると、ReturnOne()の呼び出しはスキップされます。

static IEnumerable<int> OneThroughFive()
{
    ReturnOne();
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
}

static IEnumerator<int> ReturnOne()
{
    yield return 1;
}

私がやっていることは有効ではないので、コンパイラがそれを取り除いているとしか思えません。列挙をさまざまなメソッドに分離できるようにしたいと思います。これは可能ですか?

4

1 に答える 1

38

の結果を実際に使用しているわけではありませんReturnOne。メソッドを呼び出し、戻り値を無視しています...つまり、実行されているコードが実際に表示されることはありません。あなたはこのようにそれを行うことができます:

static IEnumerable<int> OneThroughFive()
{
    foreach (int x in ReturnOne())
    {
        yield x;
    }
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
}

C#には(現在少なくとも:)一種の「すべてを譲る」構造はありません。

あなたがそれに足を踏み入れていないという事実は、あなたがイテレータブロック内に呼び出しを持っているという事実とは何の関係もありません-それはあなたがイテレータブロックの結果を使い始めるまで、どのコードも実行されないということです。そのため、引数の検証と譲歩を区別する必要があります。たとえば、次のコードについて考えてみます。

public IEnumerator<string> ReturnSubstrings(string x)
{
    if (x == null)
    {
         throw ArgumentNullException();
    }
    for (int i = 0; i < x.Length; i++)
    {
         yield return x.Substring(i);
    }
}
...
ReturnSubstring(null); // No exception thrown

あなたはそれをこのように書く必要があります:

public IEnumerator<string> ReturnSubstrings(string x)
{
    if (x == null)
    {
         throw ArgumentNullException();
    }
    return ReturnSubstringsImpl(x);
}

private IEnumerator<string> ReturnSubstringsImpl(string x)
{
    for (int i = 0; i < x.Length; i++)
    {
         yield return x.Substring(i);
    }
}

詳細については、C#の第6章を詳細に読んでください。これは、初版ではたまたま無料の章です:)ここで入手してください

于 2010-03-23T23:22:57.413 に答える