为什么要输入以下代码:
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");
}
}
唯一的区别是产量。导致不同结果且不会导致相同错误的是什么?
答案 0 :(得分:10)
任何包含yield break
或yield 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。