yield关键字是c#中一直困扰我的关键字之一,我从来都不确定自己是否正确地使用了它。

在以下两段代码中,哪一段是首选的,为什么?

版本1:使用收益率

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        foreach (Product product in products)
        {
            yield return product;
        }
    }
}

版本2:返回列表

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList<Product>();
    }
}

当前回答

以下是Chris Sells在《c#程序设计语言》中讲述的语句;

I sometimes forget that yield return is not the same as return , in that the code after a yield return can be executed. For example, the code after the first return here can never be executed: int F() { return 1; return 2; // Can never be executed } In contrast, the code after the first yield return here can be executed: IEnumerable<int> F() { yield return 1; yield return 2; // Can be executed } This often bites me in an if statement: IEnumerable<int> F() { if(...) { yield return 1; // I mean this to be the only thing returned } yield return 2; // Oops! } In these cases, remembering that yield return is not “final” like return is helpful.

其他回答

以下是Chris Sells在《c#程序设计语言》中讲述的语句;

I sometimes forget that yield return is not the same as return , in that the code after a yield return can be executed. For example, the code after the first return here can never be executed: int F() { return 1; return 2; // Can never be executed } In contrast, the code after the first yield return here can be executed: IEnumerable<int> F() { yield return 1; yield return 2; // Can be executed } This often bites me in an if statement: IEnumerable<int> F() { if(...) { yield return 1; // I mean this to be the only thing returned } yield return 2; // Oops! } In these cases, remembering that yield return is not “final” like return is helpful.

直接返回列表。好处:

这样就更清楚了 该列表是可重用的。(迭代器不是)不是真的,谢谢Jon

You should use the iterator (yield) from when you think you probably won't have to iterate all the way to the end of the list, or when it has no end. For example, the client calling is going to be searching for the first product that satisfies some predicate, you might consider using the iterator, although that's a contrived example, and there are probably better ways to accomplish it. Basically, if you know in advance that the whole list will need to be calculated, just do it up front. If you think that it won't, then consider using the iterator version.

Yield return对于需要遍历数百万个对象的算法来说非常强大。考虑以下示例,您需要计算可能的拼车行程。首先我们生成可能的行程:

    static IEnumerable<Trip> CreatePossibleTrips()
    {
        for (int i = 0; i < 1000000; i++)
        {
            yield return new Trip
            {
                Id = i.ToString(),
                Driver = new Driver { Id = i.ToString() }
            };
        }
    }

然后迭代每一次旅行:

    static void Main(string[] args)
    {
        foreach (var trip in CreatePossibleTrips())
        {
            // possible trip is actually calculated only at this point, because of yield
            if (IsTripGood(trip))
            {
                // match good trip
            }
        }
    }

如果您使用List而不是yield,您将需要为内存分配100万个对象(~190mb),而这个简单的示例将花费~1400ms运行。但是,如果使用yield,就不需要将所有这些临时对象都放到内存中,而且算法速度会大大加快:本例只需要大约400ms就可以运行,完全不消耗内存。

在这种情况下,我将使用代码的版本2。由于您拥有可用产品的完整列表,而这正是此方法调用的“消费者”所期望的,因此需要将完整的信息发送回调用方。

如果该方法的调用者一次只需要“一个”信息,而下一个信息的消耗是按需的,那么使用yield return将是有益的,它将确保当一个单位的信息可用时,执行命令将返回给调用者。

可以使用yield return的例子如下:

复杂的,一步一步的计算,调用者每次等待一个步骤的数据 在GUI中分页-用户可能永远不会到达最后一页,只有子集的信息需要在当前页面上公开

为了回答你的问题,我会使用版本2。

那么这个呢?

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList();
    }
}

我想这里干净多了。不过,我手头没有VS2008可以检查。 在任何情况下,如果Products实现了IEnumerable(似乎-它在foreach语句中使用),我将直接返回它。