2013-01-01 6 views
14

Enumerable.GroupByおよびQueryable.GroupBy拡張機能には8つのオーバーロードがあります。 (Enumerable.GroupBy用)それらのうちの2つは、以下のとおりです。elementSelectorおよびresultSelectorを持つGroupBy

// (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のために同じ、だけではなく、Func<...Expression<Func<...付き)

(b)がパラメータとして追加elementSelectorを持っています。

MSDNでan example for overload (a)およびan example for overload (b)です。同じ例のソースコレクションを持つ彼らは、仕事の両方:

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 } 
}; 

例は、(a)は、このクエリを使用しています。

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) 
    }); 

そして例(b)は、このクエリを使用しています。

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() 
    }); 

結果両方のクエリの正確に同じです。

質問1:resultSelectorを単独で使用し、実際にはelementSelectorが必要なクエリはありませんか?または、2つのオーバーロードの機能が常に同等で、どちらか一方を使用するのは単なる味の問題ですか?

質問2:LINQクエリ構文を使用すると、2つの異なるオーバーロードの対応がありますか? IEnumerableをするために:(Entity FrameworkのとQueryable.GroupByを使用する場合、両方のオーバーロードを正確に同じSQLに変換される側の問題として?)

答えて

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) 
    }); 

のにequevalentれます

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を使用すると、resultSelectorの式を簡略化できます(次と前の比較)。

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ではそれほど単純ではありません。あなたは、このメソッドのソースを見ることができます:あなたが見ることができるように

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) } 
        )); 
     } 

が、彼らは別の表現を返しますので、私はその結果のSQLクエリはすべてのケースで同じになりますわからないんだけど、私はそのSQLを想定elementSelector + resultSelectorを使用したオーバーロードのクエリは、elementSelectorなしのオーバーロードと比較して遅くなりません。

回答1:いいえ、IEnumerableでは、resultSelectorだけを使用して表現できないクエリはありません。

回答2.いいえ、LINQクエリ構文を使用する場合、2つの異なるオーバーロードに対応するものはありません。拡張メソッドには、LINQクエリ構文と比較して多くの可能性があります。

回答3(この質問に対して):このオーバーロードでは、SQLクエリが同じであるとは限りません。

関連する問題