为什么使用 yield return 的代码可以编译通过?

3

正如您所预期的那样,这段代码会产生编译器错误:

public static IEnumerable<int> Foo()
{
}

并非所有代码路径都返回一个值

然而,这段代码会编译通过,但会提示存在无法到达的代码:

public static IEnumerable<int> Foo()
{
    if(false)
    {
        yield return 0;
    }
}

这会生成一个空的可枚举对象。为什么这样做有效,并且是否定义了这种行为?

哇,如果这是真的,我非常赞赏C#编译器。@mjwills - JamieT
1
@JamieTaylorSangerman,实际上正好相反。据我理解,编译器非常愚蠢——它只是说“好的,我看到了一个yield return”。它不会尝试进行过度的可达性分析等等。 - mjwills
1个回答

7
public static IEnumerable<int> Foo()
{
}

第一个没有返回值(因此编译器会报错)。这是有道理的 - 它没有足够的上下文来知道该做什么。它应该返回null吗?一个空可枚举对象?它不知道 - 所以它不允许你编译。
public static IEnumerable<int> Foo()
{
    if(false)
    {
        yield return 0;
    }
}

第二段代码确实包含一个 yield return (即使不可到达), 这足以让它知道您想要返回一个可枚举对象(因此可以设置必要的状态机)。现在,当代码执行时,你实际上从未到达那个 yield return 行(因此编译器会发出警告) - 所以调用者获得的是一个空的可枚举对象。 这是预期的

如果函数末尾没有 yield break,编译器将假定有一个(yield break),就像普通函数中的 return; 语句一样。

考虑到第二个代码示例的丑陋和不直观,您可能希望改用:
public static IEnumerable<int> Foo()
{
    yield break;
}

由于编译后更清晰明确,编译器也不会抱怨代码无法到达。


在我的实际代码中,条件测试了一个变量。我看着我刚写的东西,想知道为什么我没有得到编译器错误。有趣的小问题。 - StackOverthrow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接