2013-01-01 40 views
14

Enumerable.GroupBy और Queryable.GroupBy एक्सटेंशन में 8 ओवरलोड हैं। उन्हें (Enumerable.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 के लिए एक ही है, बस Expression<Func<... बजाय Func<... साथ)

(b) एक अतिरिक्त elementSelector पैरामीटर के रूप में है।

एमएसडीएन पर 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 } 
}; 

उदाहरण (क) इस क्वेरी का उपयोग करता है:

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

और उदाहरण (ख) इस क्वेरी का उपयोग करता है:

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: क्या LINQ क्वेरी सिंटैक्स का उपयोग करते समय दो अलग ओवरलोड के लिए कोई समकक्ष है?

(एक तरफ सवाल के रूप में: जब इकाई की रूपरेखा के साथ Queryable.GroupBy उपयोग करते हुए, दोनों भार के ठीक उसी एसक्यूएल में अनुवाद किया जाएगा?)

उत्तर

15

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

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

तत्व का उपयोग कर चयनकर्ता चयन में अभिव्यक्ति को सरल बना सकता है चयनकर्ता (अगले और पिछले की तुलना करें):

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 तत्व के साथ ओवरलोड के लिए क्वेरी चयनकर्ता + परिणाम चयनकर्ता तत्व के बिना अधिभार की तुलना में धीमी गति से तुलना नहीं करेगा चयनकर्ता।

उत्तर 1: नहीं, IENumerable के लिए कोई प्रश्न नहीं है जिसे आप अकेले resultSelector का उपयोग करके व्यक्त नहीं कर सकते हैं।

उत्तर 2. नहीं, LINQ क्वेरी सिंटैक्स का उपयोग करते समय दो अलग ओवरलोड के लिए कोई समकक्ष नहीं है। विस्तार विधियों में LINQ क्वेरी सिंटैक्स की तुलना में अधिक संभावनाएं हैं।

उत्तर 3 (साइड प्रश्न के लिए): यह गारंटी नहीं है कि एसक्यूएल प्रश्न इस ओवरलोड के लिए समान होंगे।