以下请求是否自动“优化”?
var result = initial
.Where(Predicate1)
.Where(Predicate2)
.Where(Predicate3);
这相当于
var result = initial
.Where(e => Predicate1(e) && Predicate2(e) && Predicate3(e));
这两个陈述中哪一个更优化了两个?或者它们是否相同?
答案 0 :(得分:9)
虽然编译后的代码没有组合谓词,但执行本质上也是如此。 Linq的Where方法在传递List时返回WhereListIterator。 WhereListIterator具有自己的Where方法实现,该实现返回具有组合谓词的新WhereListIterator。它看起来像这样:
return new Enumerable.WhereListIterator<T>(this.source, Enumerable.CombinePredicates<T>(this.predicate, predicate)
其中this.source是List,this.predicate是第一个Where的谓词,而谓词来自第二个Where。
CombinePredicates返回包含以下代码的委托:
if (predicate1(source)) return predicate2(source);
return false;
所以链接的Where子句最终应该是这样的:
if (predicate1(source)) {
if (predicate2(source) {
return predicate3(source) {
}
return false;
}
return false;
使用小列表,使用&amp;&amp;将谓词组合在一起可能更有效,但随着列表大小的增加,两个选项的运行时间可能会变得相似。您必须对其进行分析以量化差异。我怀疑它不够重要。
答案 1 :(得分:6)
不,不是。这些Where
方法调用不会合并为一个。
c#code:
var input = new List<string>();
var output = input.Where(x => x.StartsWith("test")).Where(x => x.Length > 10).Where(x => !x.EndsWith("test"));
IL生成:
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_000c: brtrue.s IL_001f
IL_000e: ldnull
IL_000f: ldftn bool ConsoleApplication2.Program::'<Main>b__0'(string)
IL_0015: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_001a: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_001f: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0024: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_0029: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_002e: brtrue.s IL_0041
IL_0030: ldnull
IL_0031: ldftn bool ConsoleApplication2.Program::'<Main>b__1'(string)
IL_0037: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_003c: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_0041: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_0046: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_004b: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0050: brtrue.s IL_0063
IL_0052: ldnull
IL_0053: ldftn bool ConsoleApplication2.Program::'<Main>b__2'(string)
IL_0059: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_005e: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0063: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0068: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_006d: pop
IL_006e: ret
如您所见,有3 System.Linq.Enumerable::Where<string>
次来电。