收益率返回和“并非所有代码路径都返回值”

时间:2018-12-16 09:16:50

标签: c# yield-return

为什么要输入以下代码:

private static IEnumerable<int> TestYield(bool check)
{
    if (check)
    {
        return 1;
    }
    else
    {
        Console.WriteLine("In the else");
    }
}

产生错误,提示“并非所有代码路径都返回值”。 但是,以下代码不会产生相同的错误:

private static IEnumerable<int> TestYield(bool check)
{
    if (check)
    {
        yield return 1;
    }
    else
    {
        Console.WriteLine("In the else");
    }
}

唯一的区别是产量。导致不同结果且不会导致相同错误的是什么?

3 个答案:

答案 0 :(得分:10)

任何包含yield breakyield return语句的方法主体都是 iterator块。在迭代器块内,执行到达方法的右括号是可以接受的,因为这等效于使用yield break-这是序列的结尾。

在具有非void返回类型的常规方法中,语句的右花括号可到达是错误的。 (此外,return 1;在返回类型为IEnumerable<int>的常规方法中不是有效的语句。)

答案 1 :(得分:6)

当您只使用return时,由于您的else语句不返回任何东西,它给您您提到的错误,并且由于您返回int类型,它还给出错误“无法将表达式类型int转换为返回类型IEnumerable”

使用yield return时,yield关键字在后台创建一个状态机来维护状态信息。根据{{​​3}}的说法:“当在迭代器方法中达到yield return语句时,将返回表达式,并保留代码中的当前位置。在下次调用迭代器函数时,将从该位置重新开始执行。 “

现在,对于您的问题“其他方面会发生什么”,我来看一下用ILSpy生成的IL代码。我创建了一个名为YTest的类,并添加了返回yield的方法。这是生成的代码:

internal class YTest
{
    [IteratorStateMachine(typeof(YTest.<TestYield>d__0))]
    public static IEnumerable<int> TestYield(bool check)
    {
        int num;
        while (num == 0)
        {
            if (!check)
            {
                Console.WriteLine("In the else");
                IL_52:
                yield break;
            }
            yield return 1;
        }
        if (num != 1)
        {
            yield break;
        }
        goto IL_52;
    }
}

编译器在幕后添加了yield break语句。

使用yield关键字时,应将这些点保留在    头脑(除了msdn之外,引用MSDN

):

  
      
  • 您不能在try-catch块中包含yield return语句,尽管可以将其包含在try-finally块中

  •   
  • 您不能在finally块中包含yield break语句

  •   
  • 使用了yield的方法的返回类型应该是IEnumerable,IEnumerable,IEnumerator或IEnumerator

  •   
  • 您的方法中使用了yield的方法中不能有ref或out参数

  •   
  • 您不能在匿名方法中使用“ yield return”或“ yield break”语句

  •   
  • 您不能在“不安全”方法(即标有
    的方法)中使用“收益回报”或“收益中断”语句   “不安全”关键字表示不安全的上下文

  •   

答案 2 :(得分:0)

在您的第一个代码中,您仅返回1(它是单个整数值),但是方法的返回类型为

IEnumerable<int>

根据Microsoft;他们明确表示您应该使用

 yield return statement to return each element one at a time. 

您通过使用foreach语句或 LINQ 查询来消耗迭代器方法。因此,基本上,如果您不想进行迭代,则无需使用yield和IEnumerable,但如果您真的想对数据或文件进行迭代,则应使用 yield

有关详细信息,请阅读Yield by MS