2013-08-06 21 views
5

Aşağıdaki istek otomatik olarak "optimize edildi" mi?Çoklu ortamların en iyi şekilde kullanımı İfadelerin bulunduğu yerler

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

Bu, bu tabloların bir daha ikisinden optimize edilmiştir

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

eşdeğerdir? Yoksa aynı mı?

+0

Ne demek _best way_? Bu benim görüşüme göre doğru değil .. –

+0

Hayır, bu gerçekleşmez. Çözmeyi denediğiniz asıl sorun nedir? –

+0

@Soner: "en temiz", daha verimli. – Toto

cevap

8

Derlenmiş kod yüklemleri birleştirmemesine rağmen, yürütme esas olarak gerçekleştirir. Linq's Yöntem, bir Listeyi geçtiğinde bir WhereListIterator döndürür. WhereListIterator, yüklemlerin bir araya getirildiği yeni bir WhereListIterator döndüren kendi Where yöntemi uygulamasına sahiptir. Bu şuna benzer: this.source Liste olduğu

return new Enumerable.WhereListIterator<T>(this.source, Enumerable.CombinePredicates<T>(this.predicate, predicate)

, this.predicate Nerede ilk yüklem ve yüklem nerede ikinci arasındadır. birleştirmek & & kullanarak, küçük bir liste ile

if (predicate1(source)) { 
    if (predicate2(source) { 
     return predicate3(source) { 
    } 
    return false; 
} 
return false; 

: Yani zincirleme

if (predicate1(source)) return predicate2(source); 
return false; 

maddeleri gibi bir şey ile bitirmek gerekir:

CombinePredicates aşağıdaki kodu içeren bir temsilci döndürür tekli olarak tahmin eder Büyük olasılıkla daha verimli olan, ancak liste boyutu arttıkça, iki seçeneğin çalışma zamanı benzer hale gelebilir. Farkın ne olduğunu ölçmek için onu izlemelisin. Çok fazla önemli olmadığını sanmıyorum.

+0

Bu oldukça ilginç. –

+1

Harika cevap! Sadece 'Enumerable.Where' uygulamasını kontrol ettim ve haklısın! Yeni bir şeyler öğrenmek için her zaman vardır. – MarcinJuraszek

6

Hayır, öyle değil. Bu Where yöntemlerinin çağrıları bir arada birleştirilmez.

C# kodu:

var input = new List<string>(); 

var output = input.Where(x => x.StartsWith("test")).Where(x => x.Length > 10).Where(x => !x.EndsWith("test")); 

IL oluşturulan: Gördüğünüz gibi

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> çağrıları vardır.

+0

Her ne kadar etkili bir şekilde kısa devre değerlendirmesi ile aynı şey olduğuna inanıyorum. – JosephHirn

+0

@Ginosaji Evet, aynı, ancak derleyici bunu optimize etmiyor. Bunu kendi başına yapmalısın. – MarcinJuraszek

İlgili konular