2011-03-04 16 views
12

yazma için (mantıksal/performans) fark var vs ve operatör:linq şekillendirme, zincirleme burada maddesi

ATable.Where(x=> condition1 && condition2 && condition3)

veya

ATable.Where(x=>condition1).Where(x=>condition2).Where(x=>condition3)

ilkinden kullanıyorum ama bununla birlikte, bir sorguyu daha kolay kullanabilmek için bir sorgunun bölümlerini okuyabilir ve kopyalayabilirim. Herhangi bir düşünce?

cevap

22

Kısa cevap
Sen de aynı koleksiyona değerlendirecek şekilde uygulamanızda daha okunabilir ve sürdürülebilir olduğunu hissetmek yapmalı. derleyici yalnızca bir temsilci ve bir derleyici oluşturulan yöntemi oluşturmak gerekiyor edecek tek yüklem ifadesi olmadığı için

Uzun cevapoldukça uzun

Linq To Bu örnek için
ATable.Where(x=> condition1 && condition2 && condition3) Nesneleri . reflektör itibaren

if (CS$<>9__CachedAnonymousMethodDelegate4 == null) 
{ 
    CS$<>9__CachedAnonymousMethodDelegate4 = new Func<ATable, bool>(null, (IntPtr) <Main>b__0); 
} 
Enumerable.Where<ATable>(tables, CS$<>9__CachedAnonymousMethodDelegate4).ToList<ATable>(); 

derleyici oluşturulan yöntemi:

[CompilerGenerated] 
private static bool <Main>b__0(ATable m) 
{ 
    return ((m.Prop1 && m.Prop2) && m.Prop3); 
} 

yalnızca bir Where uzatma yöntemi vardı beri beklendiği gibi temsilci ile Enumerable.Where<T> içine sadece bir arama olduğunda görebileceğiniz gibi . Bu örnek için şimdi çok daha fazla kod üretildi


ATable.Where(x=>condition1).Where(x=>condition2).Where(x=>condition3). üç zincirleme Uzatma yöntemleri var yana

if (CS$<>9__CachedAnonymousMethodDelegate5 == null) 
    { 
     CS$<>9__CachedAnonymousMethodDelegate5 = new Func<ATable, bool>(null, (IntPtr) <Main>b__1); 
    } 
    if (CS$<>9__CachedAnonymousMethodDelegate6 == null) 
    { 
     CS$<>9__CachedAnonymousMethodDelegate6 = new Func<ATable, bool>(null, (IntPtr) <Main>b__2); 
    } 
    if (CS$<>9__CachedAnonymousMethodDelegate7 == null) 
    { 
     CS$<>9__CachedAnonymousMethodDelegate7 = new Func<ATable, bool>(null, (IntPtr) <Main>b__3); 
    } 
    Enumerable.Where<ATable>(Enumerable.Where<ATable>(Enumerable.Where<ATable>(tables, CS$<>9__CachedAnonymousMethodDelegate5), CS$<>9__CachedAnonymousMethodDelegate6), CS$<>9__CachedAnonymousMethodDelegate7).ToList<ATable>(); 

biz de üç Func<T> s almak ve ayrıca üç derleyici oluşturulan yöntemler.

[CompilerGenerated] 
private static bool <Main>b__1(ATable m) 
{ 
    return m.Prop1; 
} 

[CompilerGenerated] 
private static bool <Main>b__2(ATable m) 
{ 
    return m.Prop2; 
} 

[CompilerGenerated] 
private static bool <Main>b__3(ATable m) 
{ 
    return m.Prop3; 
} 

Şimdi bu daha yavaş olmalı, çünkü heck daha ton oluyor. Ancak, tüm yürütme GetEnumerator() aranana kadar ertelendiğinden, fark edilebilir bir farkın kendini göstereceğinden şüphe duyuyorum.

performans

  • zincirinde GetEnumerator metoduna yapılacak herhangi çağrısı bir koleksiyon iterated neden olur etkisi olabilir Bazı Sorunlar. ATable.Where().ToList().Where().ToList(), ToList çağrıldığında ve ikinci ToList ile başka bir yineleme olduğunda, ilk yüklemeyle koleksiyonun yinelenmesiyle sonuçlanır. Toplamanın yinelenen sayısını azaltmak için GetEnumerator'ı en son anı tutmaya çalışın.Biz hepsi bir arada bizim Normal Func<T, bool>

    Örnek yerine Expresssion<Func<T, bool>> kullandığınız olarak varlıkları
    için

Linq biz IQueryable<T> şimdi bizim derleyici oluşturulan kodu kullanarak bu yana biraz daha farklıdır.
var allInOneWhere = entityFrameworkEntities.MovieSets.Where(m => m.Name == "The Matrix" && m.Id == 10 && m.GenreType_Value == 3);

Bu, bir deyim oluşturuyor.

IQueryable<MovieSet> allInOneWhere = Queryable.Where<MovieSet>(entityFrameworkEntities.MovieSets, Expression.Lambda<Func<MovieSet, bool>>(Expression.AndAlso(Expression.AndAlso(Expression.Equal(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(MovieSet), "m"), (MethodInfo) methodof(MovieSet.get_Name)), ..tons more stuff...ParameterExpression[] { CS$0$0000 }));

en önemli biz Expression.AndAlso parçalara aşağı ayrıştırılır tek İfade ağacının ile bitirmek olmasıdır. Ve beklenen da benzeri sadece ben yolu uzun, bunun için derleyici kod yapıştırma rahatsız bile alışkanlık Queryable.Where

var chainedWhere = entityFrameworkEntities.MovieSets.Where(m => m.Name == "The Matrix").Where(m => m.Id == 10).Where(m => m.GenreType_Value == 3);

bir telefon var. Ama kısaca, Queryable.Where(Queryable.Where(Queryable.Where()))'a üç çağrı ve üç ifade ile sonuçlanıyoruz. Bu, üç zincirli Where maddesi olduğu için tekrar bekleniyor. listeleyicisi denir dek IEnumerable<T>IQueryable<T> gibi Sql
Oluşturulan

da yürütmüyor.

SELECT 
[Extent1].[AtStore_Id] AS [AtStore_Id], 
[Extent1].[GenreType_Value] AS [GenreType_Value], 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name] 
FROM [dbo].[MovieSet] AS [Extent1] 
WHERE (N'The Matrix' = [Extent1].[Name]) AND (10 = [Extent1].[Id]) AND (3 = [Extent1].[GenreType_Value]) 

performans etkisi olabilir Bazı Sorunlar

  • zincirinde GetEnumerator metoduna yapılacak herhangi bir çağrı çağrı neden olur: Bu nedenle biz de aynı tam sql deyimi üretmek olduğunu bilmek mutlu olabilir sql için, örneğin ATable.Where().ToList().Where() aslında ilk yüklemeyle eşleşen tüm kayıtlar için sql'yi sorgulayacak ve ardından listeyi linq ile ikinci yüklemeyle nesnelere filtreleyecektir. Başka kullanmak yüklemler ayıklanması söz yana
  • nerede, onlar Expression<Func<T, bool>> üstelik bu sadece Func<T, bool> şeklindedir emin olun. İlk bir ifade ağacına ayrıştırılabilir ve geçerli sql'ye dönüştürülebilir, ikincisi TÜM OBJECTS döndürülür ve Func<T, bool> bu koleksiyonda yürütülür.

Umarız bu, sorunuzu cevaplamak için biraz yardımcı oldu.

+2

Derinlemesine cevap işareti için teşekkürler! :) – Joe

+1

+1 Mükemmel bir yanıt için –

+1

+1 müthiş bir cevap için teşekkürler –