2011-11-24 9 views
5

मैं IEnumerable के लिए दो एक्सटेंशन मिल गया है:एक्सटेंशन IEnumerable सामान्य

public static class IEnumerableGenericExtensions 
{ 
    public static IEnumerable<IEnumerable<T>> InSetsOf<T>(this IEnumerable<T> source, int max) 
    { 
     List<T> toReturn = new List<T>(max); 
     foreach (var item in source) 
     { 
      toReturn.Add(item); 
      if (toReturn.Count == max) 
      { 
       yield return toReturn; 
       toReturn = new List<T>(max); 
      } 
     } 
     if (toReturn.Any()) 
     { 
      yield return toReturn; 
     } 
    } 

    public static int IndexOf<T>(this IEnumerable<T> source, Predicate<T> searchPredicate) 
    { 
     int i = 0; 
     foreach (var item in source) 
      if (searchPredicate(item)) 
       return i; 
      else 
       i++; 

     return -1; 
    } 
} 

तब मैं इस कोड को लिखें:

 Pages = history.InSetsOf<Message>(500); 
     var index = Pages.IndexOf(x => x == Pages.ElementAt(0)); 

जहां सार्वजनिक वर्ग इतिहास: IEnumerable लेकिन एक परिणाम के रूप में मैं मुझे उम्मीद है कि '0' नहीं है, लेकिन '-1'। मैं समझ नहीं पा रहा हूं - ऐसा क्यों?

उत्तर

5

जब आप Pages.IndexOf(x => x == Pages.ElementAt(0)); लिखते हैं, आप वास्तव में InSetsOfकई बार, deferred execution (उर्फ आलसी) की वजह से चलाते हैं। विस्तार करने के लिए:

  • Pages = history.InSetsOf<Message>(500) - इस लाइन InSetsOf बिल्कुल नहीं चलता है।
  • Pages.IndexOf - Pages से अधिक Iterates, इसलिए यह एक बार InSetsOf निष्पादित करना शुरू कर देता है।
  • x == Pages.ElementAt(0) - यह InSetsOf को फिर से निष्पादित करता है, एक बार Pages के संग्रह में प्रत्येक तत्व के लिए (या कम से कम searchPredicate वापस लौटता है, जो यहां नहीं होता है)।

हर बार जब आप InSetsOf चलाने आप एक नई सूची बनाने (विशेष रूप से, एक नया पहली सूची है, क्योंकि आप ElementAt(0) उपयोग करें)। ये दो अलग-अलग वस्तुएं हैं, इसलिए उनके बीच == की तुलना विफल हो जाती है।

एक बेहद आसानी से ठीक एक सूची वापस करने के लिए होगा, इसलिए Pages एक आस्थगित क्वेरी नहीं है, लेकिन एक ठोस संग्रह:

Pages = history.InSetsOf<Message>(500).ToList(); 

एक अन्य विकल्प है SequenceEqual उपयोग करने के लिए है, हालांकि मैं पहली बार कैशिंग की सलाह देते हैं वैसे भी तत्व:

Pages = history.InSetsOf<Message>(500); 
var firstPage = Pages.FirstOrDefault(); 
var index = Pages.IndexOf(x => x.SequenceEqual(firstPage)); 
+0

बहुत बहुत धन्यवाद! मैं इस LINQ विशिष्टता के बारे में पूरी तरह से भूल गया हूँ। – Seekeer

+0

@ सेकरियर - कोई समस्या नहीं, मदद करने में खुश! यह एक बुरा मुद्दा है - ऐसी गलतियों को करना आसान है। सबसे बुरा हिस्सा तब होता है जब आप * एक बग नहीं देखते हैं, लेकिन कोड अच्छी तरह से काम करता प्रतीत होता है, लेकिन वास्तव में बहुत धीमी है। (बग से अलग, यहां 'टोलिस्ट' के साथ या बिना जटिलता में एक बड़ा अंतर है) – Kobi

+0

हाँ, मैं लोगों को समझना शुरू कर रहा हूं, जो LINQ पसंद नहीं करते हैं। वैसे, क्या आप LINQ क्वेरी दक्षता और अनुकूलित करने पर किसी भी अच्छे आलेख/पुस्तक की अनुशंसा कर सकते हैं? – Seekeer

1

क्या आपकी कक्षा टी आईसीओपरपेबल को लागू करती है? यदि नहीं, तो आपकी समानता जांच त्रुटिपूर्ण हो सकती है, क्योंकि ढांचे को बिल्कुल पता नहीं होता है कि टी = टी। आप अपने वर्ग टी पर बराबर ओवरराइड करके भी प्राप्त करेंगे।