6

以下请求是否自动“优化”?

var result = initial
                .Where(Predicate1)
                .Where(Predicate2)
                .Where(Predicate3);

这相当于

var result = initial
                .Where(e => Predicate1(e) && Predicate2(e) && Predicate3(e));

这两个语句中哪一个更优化?还是它们相同?

4

2 回答 2

10

尽管编译后的代码没有结合谓词,但执行本质上是结合了谓词。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;

对于一个小列表,使用 && 将谓词组合在一个 Where 中可能更有效,但随着列表大小的增加,两个选项的运行时间可能会变得相似。您必须对其进行分析以量化差异是什么。我怀疑它不够大,不重要。

于 2013-08-06T13:28:41.287 回答
6

不,这不对。这些Where方法调用没有合并为一个。

c#代码:

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>调用。

于 2013-08-06T13:04:29.847 回答