正确使用“收益回报”
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>();
}
}
当我计算列表中的下一个项目(甚至下一组项目)时,我倾向于使用yield-return。
使用你的版本2,你必须在返回之前有完整的列表。 通过使用yield-return,你只需要在返回之前拥有下一个项目。
除此之外,这有助于在更大的时间范围内传播复杂计算的计算成本。 例如,如果列表连接到GUI并且用户永远不会到最后一页,则永远不会计算列表中的最终项目。
如果IEnumerable表示无限集,另一种情况是yield-return更可取。 考虑素数列表,或随机数字的无限列表。 你永远不能一次返回完整的IEnumerable,所以你使用yield-return来递增返回列表。
在你的特定例子中,你有完整的产品列表,所以我会使用版本2。
填充临时列表就像下载整个视频一样,而使用yield
则类似于流式传输视频。
作为理解何时应该使用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()
的调用可能需要很长时间,因为您必须在返回之前完成列表:
//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,因为您已经拥有完整的列表。
链接地址: http://www.djcxy.com/p/9097.html上一篇: Proper use of 'yield return'
下一篇: Usefulness of yield