C#懒惰问题

时间:2011-04-12 11:51:52

标签: c# linq

设计应用程序的常用方法是什么,它强烈依赖于C#LINQIEnumerableIQueryable,...)中的延迟评估?

现在我通常尝试使用yield returnLINQ查询使每个查询尽可能地懒惰,但在运行时这通常会导致“太懒”行为,当每个查询从它开始构建时,显然会导致严重的视觉性能下降。

我通常做的是将ToList()投影操作符放在某处缓存数据,但我怀疑这种方法可能不正确。

从一开始就设计这类应用程序的适当/常用方法是什么?

6 个答案:

答案 0 :(得分:4)

我发现将每个IEnumerable分类为三个类别之一很有用。

  1. 快速的 - 例如列表和数组
  2. 慢的 - 例如数据库查询或繁重的计算
  3. 非确定性的 - 例如list.Select(x => new {...})
  4. 对于类别1,我倾向于在适当的时候保留具体类型,数组或IList等。 对于类别3,最好将本地保留在方法中,以避免难以发现的错误。 然后我们有类别2,并且在优化性能时,一如既往地测量以找到瓶颈。

答案 1 :(得分:2)

一些随意的想法 - 因为问题本身是松散定义的:

  • 只有在不使用结果时才会使用Lazy,因此仅在需要时加载。但是,大多数操作都需要加载数据,因此在该术语中懒惰并不好。
  • 懒惰可能导致困难。我们已经在ORM中的数据上下文中看到了这一切
  • 对于MEF来说,懒惰是好的

答案 2 :(得分:2)

相当广泛的问题,不幸的是你会听到很多:这取决于。延迟加载是很好的,直到它不是。

通常,如果您反复使用相同的IEnumerables,最好将它们缓存为列表。

但是很少有人能够让你的来电者知道这一点。也就是说,如果你从存储库或其他东西获得IEnumerables,最好让存储库完成它的工作。它可能会在内部将其缓存为列表,也可能每次都将其构建。如果你的呼叫者试图变得太聪明,他们可能会错过数据的变化等等。

答案 3 :(得分:2)

我建议在返回DTO之前在DAL中执行ToList

public IList<UserDTO> GetUsers()
{
  using (var db = new DbContext())
  {
    return (from u in db.tblUsers
           select new UserDTO()
           {
               Name = u.Name
           }).ToList();
  }
}

在上面的示例中,在DbContext范围结束之前执行ToList()。

答案 4 :(得分:1)

我需要缓存某个特定的数据序列,在该序列上调用其中一个聚合运算符(ToListToArray等)。否则只需使用延迟评估。

围绕数据构建代码。什么数据是易变的,每次都需要重新提升?使用延迟评估并且不要缓存。什么数据是相对静态的,只需要拉一次?将数据缓存在内存中,这样就不会不必要地将其拉出来。

答案 5 :(得分:0)

延迟执行并使用.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;
    }
}

如果你运行Test()方法,那么_count只有10.没有缓存,它将是16而且。ToList()它将是40!

implementation of LazyList can be found here的一个例子。