2016-05-13 69 views
0

我想了解IEnumerator的收益率回报。在尝试下面的简单例子之后,我发现链中的最后一个方法首先执行。我并不期待。收益率返回改变链接调用方法的顺序

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 

但只要我删除产量的回报,并更改功能,只使用return.The方法的调用秩序。

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 

任何帮助了解这将是大加赞赏。

回答

3

随着yield return你正在创建一个隐式枚举。在这种情况下,编译器实际上做了很多代码转换。这里的要点是,只要返回值就会保存方法的状态

所以会发生什么这里基本上是你的第一个方法返回一个IEnumerable立即调用的时候,但代码对于产生价值将尚未运行。只有枚举时才会发生这种情况。该枚举发生在您的第二个方法中,该方法使用foreach。因此,您首先会看到第二个方法的输出,因为第一个方法的输出仅在生成第一个来自enumerable的值时发生。

在你的第二种情况下,你实际上并没有枚举任何东西,而是返回IEnumerable,它只会在枚举时生成/过滤值。但是,由于您的方法主体不再包含yield return,因此编译器不再会将其重写为实际上IEnumerable,它会生成值,因此这只是一种常规方法,并且会按您期望的顺序立即运行。