推迟执行列表<;T>;使用Linq

推迟执行列表<;T>;使用Linq,linq,list,generics,deferred-execution,Linq,List,Generics,Deferred Execution,假设我有一个列表,其中包含1000项 然后我将其传递给筛选此列表的方法。 当它在各种情况下运行时(例如可能有50个),List最多可能有50个对其执行的各种LinqWhere()操作 我对尽快跑步感兴趣。因此,我不希望每次对该列表执行Where()时都对其进行过滤 基本上,我需要它来推迟对列表的实际操作,直到应用了所有过滤器 这是由编译器本机完成的吗?或者当我调用IEnumerable上的.ToList()时,List.Where()返回,或者我应该对X执行Where()操作(其中X=List.

假设我有一个
列表
,其中包含1000项

然后我将其传递给筛选此列表的方法。 当它在各种情况下运行时(例如可能有50个),
List
最多可能有50个对其执行的各种Linq
Where()
操作

我对尽快跑步感兴趣。因此,我不希望每次对该
列表执行
Where()
时都对其进行过滤

基本上,我需要它来推迟对
列表的实际操作,直到应用了所有过滤器

这是由编译器本机完成的吗?或者当我调用IEnumerable上的.ToList()时,
List.Where()
返回,或者我应该对X执行
Where()
操作(其中X=List.AsQueryable())


希望这是有意义的。

是的,本机支持延迟执行。每次在列表上应用查询或lambda表达式时,查询都会存储仅在对查询调用.ToList()时执行的所有表达式。

,本机支持延迟执行。每次在列表上应用查询或lambda表达式时,查询都会存储仅在对查询调用.ToList()时执行的所有表达式。

每次调用
,其中
将创建一个新对象,该对象了解您的过滤器及其调用顺序

当这个新对象被要求输入一个值时(我故意在迭代器和iterable之间搞模糊),它会要求原始序列输入下一个值,检查过滤器,然后返回值或迭代返回,要求原始序列输入下一个值等等

因此,如果您调用
Where
50次(如在
list.Where(…).Where(…).Where(…)
中),您最终得到的结果是,对于返回的每个项目,需要在调用堆栈中上下移动至少50次。这会对性能产生多大影响?我不知道:您应该衡量它

一种可能的替代方法是构建一个表达式树,然后在最后将其编译为委托,然后调用
Where
。这当然需要付出更多的努力,但最终可能会更加高效。实际上,它可以让您改变这一点:

list.Where(x => x.SomeValue == 1)
    .Where(x => x.SomethingElse != null)
    .Where(x => x.FinalCondition)
    .ToList()
进入


如果你知道你将要结合很多“where”一起过滤,这可能会比通过
IQueryable
更有效。一如既往,在执行更复杂的操作之前,请检查最简单解决方案的性能。

每次调用
,其中
将创建一个新对象,该对象了解您的过滤器及其调用顺序

当这个新对象被要求输入一个值时(我故意在迭代器和iterable之间搞模糊),它会要求原始序列输入下一个值,检查过滤器,然后返回值或迭代返回,要求原始序列输入下一个值等等

因此,如果您调用
Where
50次(如在
list.Where(…).Where(…).Where(…)
中),您最终得到的结果是,对于返回的每个项目,需要在调用堆栈中上下移动至少50次。这会对性能产生多大影响?我不知道:您应该衡量它

一种可能的替代方法是构建一个表达式树,然后在最后将其编译为委托,然后调用
Where
。这当然需要付出更多的努力,但最终可能会更加高效。实际上,它可以让您改变这一点:

list.Where(x => x.SomeValue == 1)
    .Where(x => x.SomethingElse != null)
    .Where(x => x.FinalCondition)
    .ToList()
进入


如果你知道你将要结合很多“where”一起过滤,这可能会比通过
IQueryable
更有效。一如既往,在做更复杂的事情之前,检查最简单的解决方案的性能。

问题和评论中有太多的失败。答案很好,但没有足够的力度来突破失败

假设您有一个列表和一个查询

List<T> source = new List<T>(){  /*10 items*/ };
IEnumerable<T> query = source.Where(filter1);
query = query.Where(filter2);
query = query.Where(filter3);
...
query = query.Where(filter10);
List source=newlist(){/*10项*/};
IEnumerable query=source.Where(filter1);
query=query.Where(filter2);
query=query.Where(filter3);
...
query=query.Where(filter10);

[lazy evaluation]是由编译器本机完成的吗

不是。延迟评估是由于

此方法通过使用延迟执行来实现。立即返回值是一个存储执行操作所需的所有信息的对象。只有通过直接调用其GetEnumerator方法或使用Visual C#中的foreach或For Ea枚举该对象后,才会执行此方法表示的查询用visualbasic编程


呼叫列表中存在速度惩罚。AsQueryable().ToList()中

不要调用
AsQueryable
,您只需要使用
Enumerable.Where


因此不会阻止50个调用的深度调用堆栈


调用堆栈的深度远不如首先使用高效过滤器重要。如果您可以提前减少元素的数量,那么您可以在以后减少方法调用的数量。

问题和注释中有太多的失败。答案很好,但没有足够的力度来突破失败

假设您有一个列表和一个查询

List<T> source = new List<T>(){  /*10 items*/ };
IEnumerable<T> query = source.Where(filter1);
query = query.Where(filter2);
query = query.Where(filter3);
...
query = query.Where(filter10);
List source=newlist(){/*10项*/};
IEnumerable query=source.Where(filter1);
query=query.Where(filter2);
query=query.Where(filter3);
...
query=query.Where(filter10);

[lazy evaluation]是由编译器本机完成的吗

不是。延迟评估是由于

此方法通过使用延迟执行来实现。立即返回值是一个存储执行操作所需的所有信息的对象。此方法表示的查询不是