C# 懒惰问题
在C LINQ、IEnumerable、IQueryable……中,设计应用程序的常用方法是什么 现在,我通常尝试使用yield-return和LINQ查询使每个查询尽可能地懒惰,但在运行时,这通常会导致过于懒惰的行为,当每个查询从一开始就被构建时,显然会导致严重的视觉性能下降 我通常的做法是将ToList投影操作符放在某个地方以缓存数据,但我怀疑这种方法可能不正确C# 懒惰问题,c#,linq,C#,Linq,在C LINQ、IEnumerable、IQueryable……中,设计应用程序的常用方法是什么 现在,我通常尝试使用yield-return和LINQ查询使每个查询尽可能地懒惰,但在运行时,这通常会导致过于懒惰的行为,当每个查询从一开始就被构建时,显然会导致严重的视觉性能下降 我通常的做法是将ToList投影操作符放在某个地方以缓存数据,但我怀疑这种方法可能不正确 从一开始设计这类应用程序的合适/常用方法是什么?一些随机想法-因为问题本身的定义很松散: 只有当结果可能不被使用时,Lazy才是好
从一开始设计这类应用程序的合适/常用方法是什么?一些随机想法-因为问题本身的定义很松散: 只有当结果可能不被使用时,Lazy才是好的,因此只有在需要时才加载。然而,大多数操作都需要加载数据,因此从这个角度来看,惰性是不好的。 懒惰会导致棘手的问题。我们已经在ORMs的数据上下文中看到了这一切 说到我,懒惰是好的
如果您需要缓存特定的数据序列,请在该序列上调用一个聚合运算符ToList、ToArray等。否则,只需使用惰性评估
围绕数据构建代码。哪些数据是不稳定的,每次都需要刷新?使用延迟计算,不缓存。哪些数据是相对静态的,只需要拉取一次?将数据缓存在内存中,这样您就不会不必要地提取数据。这是一个相当广泛的问题,不幸的是,您会经常听到这一点:这取决于具体情况。延迟加载是伟大的,直到它不是 通常,如果反复使用相同的IEnumerables,最好将它们缓存为列表
但无论哪种方式,打电话的人都很少知道这一点。也就是说,如果您从存储库或其他地方获取IEnumerables,最好让存储库完成它的工作。它可能会在内部将其缓存为一个列表,或者每次都会将其建立起来。如果您的呼叫者试图变得太聪明,他们可能会错过数据的更改等。我建议在返回DTO之前在您的DAL中做一个收费列表
public IList<UserDTO> GetUsers()
{
using (var db = new DbContext())
{
return (from u in db.tblUsers
select new UserDTO()
{
Name = u.Name
}).ToList();
}
}
在上面的示例中,您必须在DbContext作用域结束之前创建一个ToList。我发现将每个IEnumerable分类为三个类别中的一个很有用 快速的-例如列表和数组 缓慢的-例如数据库查询或繁重的计算 非确定性的-例如list.Selectx=>new{…} 对于类别1,我倾向于在适当的时候保留具体类型,数组或IList等。 对于类别3,最好在方法中保持局部性,以避免难以发现的bug。
然后,我们有第2类,和往常一样,在优化性能时,首先测量以找到瓶颈。延迟执行和使用.ToList缓存所有项目不是唯一的选项。第三个选项是在使用惰性列表进行迭代时缓存项 执行仍被延迟,但所有项目仅产生一次。这是如何工作的一个示例:
public class LazyListTest
{
private int _count = 0;
public void Test()
{
var numbers = Enumerable.Range(1, 40);
var numbersQuery = numbers.Select(GetElement).ToLazyList(); // Cache lazy
var total = numbersQuery.Take(3)
.Concat(numbersQuery.Take(10))
.Concat(numbersQuery.Take(3))
.Sum();
Console.WriteLine(_count);
}
private int GetElement(int value)
{
_count++;
// Some slow stuff here...
return value * 100;
}
}
如果运行测试方法,则_计数仅为10。如果不缓存,它将是16,如果使用.ToList,它将是40
一个例子。天哪!我有一个公吨的代码,看起来几乎和这个一样