为什么'返回'和'收益率'在这个例子中有相同的行为?

时间:2014-10-03 11:34:14

标签: c# linq

我正在读这个article about fluent-style syntax,我尝试了这个例子。我注意到,当我将YoungDogs()HerdingDogs()方法体转换为LINQ表达式时,yield return被替换为return,但方法的行为保持不变。

为什么将方法更改为LINQ表达式会改变数据返回的行为?

这是文章中概述的原始示例:

    public static IEnumerable<Dog> YoungDogs(this IEnumerable<Dog> dogs)
    {
        foreach (Dog d in dogs)
            if (d.Age < 10)
                yield return d;
    }

    public static IEnumerable<Dog> HerdingDogs(this IEnumerable<Dog> dogs)
    {
        foreach (Dog d in dogs)
            if ((d.Breed == Breed.BorderCollie) ||
                (d.Breed == Breed.Collie) ||
                (d.Breed == Breed.Sheltie))
                yield return d;
    }

这是使用更改方法的完整程序:

class Program
{
    static void Main(string[] args)
    {
        foreach (Dog d in AllMyDogs().YoungDogs().HerdingDogs())
        {
            Console.WriteLine(d.ToString());
            if (d.Breed == Breed.JackRussell)
                break;
        }

        Console.ReadLine();
    }

    private static IEnumerable<Dog> AllMyDogs()
    {
        yield return new Dog("Kirby", Breed.BorderCollie, 14);
        yield return new Dog("Jack", Breed.JackRussell, 15);
        yield return new Dog("Ruby", Breed.Mutt, 4);
        yield return new Dog("Lassie", Breed.Collie, 19);
        yield return new Dog("Shep", Breed.Collie, 2);
        yield return new Dog("Foofoo", Breed.Sheltie, 8);
        yield return new Dog("Pongo", Breed.Dalmatian, 4);
        yield return new Dog("Rooster", Breed.WestHighlandTerrier, 1);
    }
}

static class DogFilters
{
    public static IEnumerable<Dog> YoungDogs(this IEnumerable<Dog> dogs)
    {
        return dogs.Where(d => d.Age < 10);
    }

    public static IEnumerable<Dog> HerdingDogs(this IEnumerable<Dog> dogs)
    {
        return dogs.Where(d => (d.Breed == Breed.BorderCollie) ||
                               (d.Breed == Breed.Collie) ||
                               (d.Breed == Breed.Sheltie));
    }
}

public enum Breed
{
    BorderCollie,
    Collie,
    Sheltie,
    JackRussell,
    Mutt,
    Dalmatian,
    WestHighlandTerrier
}

public class Dog
{
    public string Name { get; set; }
    public Breed Breed { get; set; }
    public int Age { get; set; }

    public Dog(string name, Breed breed, int age)
    {
        Name = name;
        Breed = breed;
        Age = age;
    }

    public bool TryBark(out string barkSound)
    {
        bool success = false;
        barkSound = "";

        if (Age <= 10)
        {
            success = true;
            barkSound = "Woof";
        }

        return success;
    }

    public string Bark()
    {
        string barkSound;

        if (!TryBark(out barkSound))
            throw new Exception("This dog can't bark");
        return barkSound;
    }

    public override string ToString()
    {
        return string.Format("{0} <{1}>, age {2}", Name, Breed.ToString(), Age);
    }
}

1 个答案:

答案 0 :(得分:3)

这个dogs.Where(d => d.Age < 10);声明一个序列,当将调用YoungDogs时将返回该序列。将返回的是序列的声明,而不是&#34; 通过过滤器的狗&#34;。只有在您请求时,您才能从dogs集合中获取实际对象。

引擎盖Where封装了对yield return的调用,dogs中传递谓词的项目依次返回。这种情况发生在以下的地方:

// That declares the sequence, you want to get. 
// In dogsWithAgeLessThanTen you don't have actaully any dog.
var dogsWithAgeLessThanTen = dogs.Where(d => d.Age < 10);

// Now you request the above query to be executed, that's called lazy loading. 
// Here you get one after the other the dogs that have age less than 10.
// The Enumerator you get from the dogsWithAgeLessThanTen returns your data 
// through a yield return statement.
foreach(var dog in dogsWithAgeLessThanTen)
{

}

以上是相同的,关于结果taht将返回以下一个:

public static IEnumerable<Dog> YoungDogs(this IEnumerable<Dog> dogs)
{
    foreach (Dog d in dogs)
        if (d.Age < 10)
            yield return d;
}

var dogsWithAgeLessThanTen = dogs.YoungDogs();

foreach(var dog in dogsWithAgeLessThanTen)
{

}