嵌套方法中的C#yield

Dav*_*vid 18 c# ienumerable yield

如果我单步执行以下代码,则会跳过对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;
}
Run Code Online (Sandbox Code Playgroud)

我只能假设编译器正在剥离它,因为我正在做的是无效的.我希望能够将我的枚举分离成各种方法.这可能吗?

Jon*_*eet 31

你实际上并没有使用结果ReturnOne.您正在调用该方法,并忽略返回值...这意味着您实际上从未看到任何代码正在运行.你可以这样做:

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

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
Run Code Online (Sandbox Code Playgroud)

你需要像这样写:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请阅读深度C#的第6章 - 恰好是第一版中的免费章节:) 抓住这里.

  • 我喜欢如何,在阅读此线程时,我知道 jon skeet 在我向下滚动到底部并看到作者之前写了这个答案。@jon,你真的应该多出去走走。但现在,再次感谢你教我一些新东西。 (2认同)
  • @BlueRaja:你会得到一个 ArgumentNullException - 检查仍然会执行,但只会在第一次调用 GetEnumerator() 返回的迭代器的 MoveNext() 时执行。 (2认同)