我试图通过IEnumerator了解yield return。在尝试以下简单示例后,我发现链中的最后一个方法首先执行。我并不期待。
public static void Example()
{
List<Pet> pets =
new List<Pet>{ new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 }
};
var p1 = pets.ReturnPetAgeGreatThan2().ReturnPetAgeGreatThan4();
foreach (var p in p1)
{
// Removed it to keep it simple
//Console.WriteLine("Pet Name:{0},Age:{1}", p.Name, p.Age);
}
Console.ReadLine();
}
public static IEnumerable<Pet> ReturnPetAgeGreatThan2(this IEnumerable<Pet> p)
{
Console.WriteLine("I am in ReturnPetAgeGreatThan2");
foreach (var par in p)
{
if (par.Age > 2)
yield return par;
}
}
public static IEnumerable<Pet> ReturnPetAgeGreatThan4(this IEnumerable<Pet> p)
{
Console.WriteLine("I am in ReturnPetAgeGreatThan4");
foreach (var par in p)
{
if (par.Age > 4)
yield return par;
}
}
}
输出
I am in ReturnPetAgeGreatThen4
I am in ReturnPetAgeGreatThen2
但是只要我删除yield return,并将函数更改为仅使用return。方法按顺序调用。
public static IEnumerable<Pet> ReturnPetAgeGreatThan2(this IEnumerable<Pet> p)
{
Console.WriteLine("I am in ReturnPetAgeGreatThen2");
var result = p.Where(x => x.Age > 2);
return result;
}
public static IEnumerable<Pet> ReturnPetAgeGreatThan4(this IEnumerable<Pet> p)
{
Console.WriteLine("I am in ReturnPetAgeGreatThen4");
var result = p.Where(x => x.Age > 4);
return result;
}
输出
I am in ReturnPetAgeGreatThen2
I am in ReturnPetAgeGreatThen4
非常感谢任何理解这一点的帮助。
答案 0 :(得分:3)
使用yield return
,您可以创建隐式枚举。在这种情况下,编译器实际上进行了大量的代码转换。这里的要点是,只要返回一个值,就会保存方法的 state 。
所以这里发生的事情基本上是你的第一个方法在被调用时立即返回IEnumerable
,但为其生成值的代码将无法运行。只有在枚举时才会发生这种情况。该枚举发生在您的第二个方法中,该方法使用foreach
。因此,您首先看到第二个方法的输出,因为第一个方法的输出仅在生成枚举的第一个值时发生。
在你的第二种情况下,你实际上并没有枚举任何内容,而是返回仅在枚举时生成/过滤值的IEnumerable
。但是,由于您的方法体不再包含yield return
,编译器将不再重写它实际 生成值的IEnumerable
,因此只是一种常规方法,立即按照您期望的顺序运行。