CSharp - 使用yield返回

  显示原文与译文双语对照的内容

使用它在 correctly,屈服关键字是其中的一个,C# 还继续在故弄玄虚中关键词我,我从未相信,我 am.

在下面的两个代码Fragment中,这是首选的?

使用 yield return, 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: 返回 List


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

 return products.ToList<Product>();
 }
}
时间:

你可以将第一个版本重写为:


public static IEnumerable<Product> GetAllProducts()
{
 using (AdventureWorksEntities db = new AdventureWorksEntities())
 {
 return db.Product.ToList();
 }
}

或者可能使用:


public static IEnumerable<Product> GetAllProducts()
{
 using (AdventureWorksEntities db = new AdventureWorksEntities())
 {
 return db.Product.Select(p => p).ToList();
 }
}

在LINQ到SQL的情况下,它并没有多大差别,因为结果无论如何都会被获取,我相信。 在其他情况下,流之间的数据差异让这一切都正在实用的而不是一个解决方案。

于自由它的曼宁站点上相关,如需了解有关 yield 确实,顺便说一句,读什么章 6中 C#的深度,这是 available. 我还有几个关于它的文章:

作为理解什么时候应该使用 yield的概念性示例,我们假设方法 ConsumeLoop() 处理 ProduceList() 返回/生成的项:


void ConsumeLoop() {
 foreach (Consumable item in ProduceList())//might have to wait here
 item.Consume();
}

IEnumerable<Consumable> ProduceList() {
 while (KeepProducing())
 yield return ProduceExpensiveConsumable();//expensive
}

没有 yield,对 ProduceList()的调用可能需要很长时间,因为你必须在返回之前完成 List:


//pseudo-assembly
Produce consumable[0]//expensive operation, e.g. disk I/O
Produce consumable[1]//waiting...
Produce consumable[2]//waiting...
Produce consumable[3]//completed the consumable list
Consume consumable[0]//start consuming
Consume consumable[1]
Consume consumable[2]
Consume consumable[3]

使用 yield,它就会重新排列,工作在"并行":


//pseudo-assembly
Produce consumable[0]
Consume consumable[0]//immediately Consume
Produce consumable[1]
Consume consumable[1]//consume next
Produce consumable[2]
Consume consumable[2]//consume next
Produce consumable[3]
Consume consumable[3]//consume next

最后,就像之前建议的那样,你应该使用 2版本,因为你已经完成了 List 。

这是打算中的发电机上看上去是个古怪的建议,但我学习了如何改用 yield 关键字在 C# 通过读取一 presentation: 大卫的Beazley M 。http://www.dabeaz.com/generators/Generators.pdf 。 你不需要了解很多 python 来理解演示文稿- 我没有。 我发现这对解释生成器的工作原理和你应该关注的原因非常有帮助。

这个是有点儿除了点,但是因为现在的问题是在我的两个cents,标记best-practices我会继续前进,throw. 对于这种类型的东西,我非常喜欢将它变成一个属性:


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

 return products;
 }
 }
}

当然,这是一个更多的boiler-plate,但是使用这个代码的代码看起来会更加清晰:


prices = Whatever.AllProducts.Select (product => product.price);

yf_terminology_vs@#@#@#vs_yf_terminology


prices = Whatever.GetAllProducts().Select (product => product.price);

注意: 我不会这样做的任何方法,这些方法可能需要一段时间才能完成他们的工作。

那这个?


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

 return products.ToList();
 }
}

我想这很干净。 虽然我手头没有VS2008来检查。 无论如何,如果产品实现了 IEnumerable ( 似乎- 它在foreach语句中使用),我将直接返回它。

...