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>();
}
}
这有点离题了,但由于这个问题被标记为最佳实践,我将继续发表我的意见。对于这种类型的东西,我非常喜欢把它变成一个属性:
public static IEnumerable<Product> AllProducts
{
get {
using (AdventureWorksEntities db = new AdventureWorksEntities()) {
var products = from product in db.Product
select product;
return products;
}
}
}
当然,它更像一个样板,但使用它的代码将看起来更干净:
prices = Whatever.AllProducts.Select (product => product.price);
vs
prices = Whatever.GetAllProducts().Select (product => product.price);
注意:我不会对任何可能需要一段时间才能完成工作的方法这样做。
考虑到确切的两个代码片段,我认为版本1更好,因为它可以更有效。假设有很多产品,调用者希望将其转换为dto。
var dtos = GetAllProducts().Select(ConvertToDto).ToList();
在版本2中,首先创建一个Product对象列表,然后创建另一个ProductDto对象列表。版本1没有Product对象的列表,只构建了所需的ProductDto对象的列表。
Even without converting, Version 2 has a problem in my opinion: The list is returned as IEnumerable. The caller of GetAllProducts() does not know how expensive the enumeration of the result is. And if the caller needs to iterate more than once, she will probably materialize once by using ToList() (tools like ReSharper also suggest this). Which results in an unnecessary copy of the list already created in GetAllProducts(). So if Version 2 should be used, the return type should be List and not IEnumerable.