2013-01-01 21 views
14

Enumerable.GroupBy ve Queryable.GroupBy eklentilerinde 8 aşırı yükleme var. (Enumerable.GroupBy için) bunların ikisi şunlardır: GroupBy öğesiyleSelector ve sonuçSelector

// (a) 
IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    Func<TKey, IEnumerable<TSource>, TResult> resultSelector); 

// (b) 
IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    Func<TSource, TElement> elementSelector, 
    Func<TKey, IEnumerable<TElement>, TResult> resultSelector); 

( Queryable.GroupBy için aynıdır, sadece Expression<Func<... yerine Func<... ile)

(b) parametre olarak ek elementSelector sahiptir.

MSDN, an example for overload (a) ve an example for overload (b)'dur. Aynı örnek kaynak toplama her iki çalışma:

List<Pet> petsList = new List<Pet> 
{ 
    new Pet { Name="Barley", Age=8.3 }, 
    new Pet { Name="Boots", Age=4.9 }, 
    new Pet { Name="Whiskers", Age=1.5 }, 
    new Pet { Name="Daisy", Age=4.3 } 
}; 

Örnek (a), bu sorgu kullanır:

var query = petsList.GroupBy(
    pet => Math.Floor(pet.Age), // keySelector 
    (age, pets) => new   // resultSelector 
    { 
     Key = age, 
     Count = pets.Count(), 
     Min = pets.Min(pet => pet.Age), 
     Max = pets.Max(pet => pet.Age) 
    }); 

ve Örnek (b), bu sorgu kullanır:

var query = petsList.GroupBy(
    pet => Math.Floor(pet.Age), // keySelector 
    pet => pet.Age,    // elementSelector 
    (baseAge, ages) => new  // resultSelector 
    { 
     Key = baseAge, 
     Count = ages.Count(), 
     Min = ages.Min(), 
     Max = ages.Max() 
    }); 

sonuç her iki sorgunun da aynısı.

Soru 1: resultSelector'u kullanarak ve elementSelector'a gerçekten gereksinim duyacağımı ifade edemediğim herhangi bir sorgu var mı? Ya da iki aşırı yükün yetenekleri her zaman eşdeğerdir ve bir ya da diğerini kullanmak sadece bir zevk meselesi midir?

Soru 2: LINQ sorgu sözdizimini kullanırken iki farklı aşırı yük için bir karşı taraf var mı?

(bir yan soru gibi: Entity Framework ile Queryable.GroupBy kullanırken, her iki aşırı yükler aynı SQL tercüme edilecek?) IEnumerable için

cevap

15

:

:

petsList.GroupBy(
    pet => Math.Floor(pet.Age), // keySelector 
    (age, pets) => new   // resultSelector 
    { 
     Key = age, 
     Count = pets.Count(), 
     Min = pets.Min(pet => pet.Age), 
     Max = pets.Max(pet => pet.Age) 
    }); 

için equevalent olduğunu

var query = petsList.GroupBy(
    pet => Math.Floor(pet.Age), // keySelector 
    pet => pet,    // elementSelector 
    (baseAge, ages) => new  // resultSelector 
    { 
     Key = baseAge, 
     Count = ages.Count(), 
     Min = ages.Min(pet => pet.Age), 
     Max = ages.Max(pet => pet.Age) 
    }); 

elementSelector kullanımı, sonuçtaki ifadeleri basitleştirebilir Seçici (sonraki ve önceki karşılaştır):

var query = petsList.GroupBy(
    pet => Math.Floor(pet.Age), // keySelector 
    pet => pet.Age,    // elementSelector 
    (baseAge, ages) => new  // resultSelector 
    { 
     Key = baseAge, 
     Count = ages.Count(), 
     Min = ages.Min(), //there is no lambda due to element selector 
     Max = ages.Max() ////there is no lambda due to element selector 
    }); 

IQueryable'de bu kadar basit değil. Bu yöntemlerin kaynaklarına bakabilirsiniz: Gördüğünüz gibi

public static IQueryable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, Expression<Func<TKey, IEnumerable<TElement>, TResult>> resultSelector) 
     { 
      if (source == null) 
       throw Error.ArgumentNull("source"); 
      if (keySelector == null) 
       throw Error.ArgumentNull("keySelector"); 
      if (elementSelector == null) 
       throw Error.ArgumentNull("elementSelector"); 
      if (resultSelector == null) 
       throw Error.ArgumentNull("resultSelector"); 
      return source.Provider.CreateQuery<TResult>(
       Expression.Call(
        null, 
        ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey), typeof(TElement), typeof(TResult)), 
        new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(elementSelector), Expression.Quote(resultSelector) } 
        )); 
     } 

public static IQueryable<TResult> GroupBy<TSource, TKey, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector,Expression<Func<TKey, IEnumerable<TSource>, TResult>> resultSelector) 
     { 
      if (source == null) 
       throw Error.ArgumentNull("source"); 
      if (keySelector == null) 
       throw Error.ArgumentNull("keySelector"); 
      if (resultSelector == null) 
       throw Error.ArgumentNull("resultSelector"); 
      return source.Provider.CreateQuery<TResult>( 
       Expression.Call(
        null, 
        ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey), typeof(TResult)), 
        new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(resultSelector) } 
        )); 
     } 

, farklı ifadeleri döndürür, bu yüzden o sonuç SQL sorgusu her durumda aynı olacaktır emin değilim, ama ben SQL varsayalım elementSelector + resultSelector ile aşırı yük sorgusu, elementSelector olmaksızın aşırı yüklenmeyle daha yavaş olmayacaktır.

Yanıt 1: Hayır, IEnumerable için resultSelector tek başına kullanarak ifade edemediğiniz sorgu yok.

Yanıt 2. Hayır, LINQ sorgu sözdizimini kullanırken iki farklı aşırı yük için karşı taraf yoktur. Uzatma yöntemleri, LINQ sorgu sözdizimine kıyasla daha fazla olasılık sunmaktadır.

Yanıt 3 (Yan soru için): sql sorgularının bu aşırı yüklenmeler için aynı olacağı garanti edilmez.