收益率返回会改变链式调用方法的顺序

时间:2016-05-13 23:08:59

标签: c# yield-return

我试图通过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

非常感谢任何理解这一点的帮助。

1 个答案:

答案 0 :(得分:3)

使用yield return,您可以创建隐式枚举。在这种情况下,编译器实际上进行了大量的代码转换。这里的要点是,只要返回一个值,就会保存方法的 state

所以这里发生的事情基本上是你的第一个方法在被调用时立即返回IEnumerable ,但为其生成值的代码将无法运行。只有在枚举时才会发生这种情况。该枚举发生在您的第二个方法中,该方法使用foreach。因此,您首先看到第二个方法的输出,因为第一个方法的输出仅在生成枚举的第一个值时发生。

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