Ответ 1
Для IEnumerable:
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)
});
равнозначно:
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-запрос для перегрузки с элементом elementelector + resultSelector будет не медленнее сравнивать с перегрузкой без ElementSelector.
Ответ 1: Нет, для IEnumerable нет запроса, который вы не можете выразить, используя только resultSelector
.
Ответ 2. Нет, нет дубликатов двух разных перегрузок при использовании синтаксиса запроса LINQ. Методы расширения имеют больше возможностей по сравнению с синтаксисом запроса LINQ.
Ответ 3 (для бокового вопроса): не гарантируется, что запросы sql будут одинаковыми для этих перегрузок.