2012-07-02 14 views
86

मुझे पता है कि गैर सामान्य IEnumerable लागू करने के लिए, इस तरह:मैं कैसे लागू करते हैं IEnumerable <T>

using System; 
using System.Collections; 

namespace ConsoleApplication33 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyObjects myObjects = new MyObjects(); 
      myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 }; 
      myObjects[1] = new MyObject() { Foo = "World", Bar = 2 }; 

      foreach (MyObject x in myObjects) 
      { 
       Console.WriteLine(x.Foo); 
       Console.WriteLine(x.Bar); 
      } 

      Console.ReadLine(); 
     } 
    } 

    class MyObject 
    { 
     public string Foo { get; set; } 
     public int Bar { get; set; } 
    } 

    class MyObjects : IEnumerable 
    { 
     ArrayList mylist = new ArrayList(); 

     public MyObject this[int index] 
     { 
      get { return (MyObject)mylist[index]; } 
      set { mylist.Insert(index, value); } 
     } 

     IEnumerator IEnumerable.GetEnumerator() 
     { 
      return mylist.GetEnumerator(); 
     } 
    } 
} 

हालांकि मैं भी नोटिस IEnumerable एक सामान्य संस्करण, IEnumerable<T> है, लेकिन मैं समझ नहीं कैसे कर सकते हैं इसे लागू करने के लिए।

अगर मैं अपने निर्देशों का उपयोग करने के using System.Collections.Generic; जोड़ें और फिर परिवर्तित करें:

class MyObjects : IEnumerable 

रहे हैं:

class MyObjects : IEnumerable<MyObject> 

और फिर सही IEnumerable<MyObject> पर क्लिक करें और Implement Interface => Implement Interface का चयन करें, विजुअल स्टूडियो काम आते हुए निम्नलिखित ब्लॉक कहते हैं कोड:

IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator() 
{ 
    throw new NotImplementedException(); 
} 

रिटर्न GetEnumerator(); विधि से गैर जेनेरिक आईनेमेरेबल ऑब्जेक्ट इस समय काम नहीं करता है, तो मैं यहां क्या रखूं? सीएलआई अब जेनेरिक संस्करण के लिए गैर सामान्य कार्यान्वयन और सिर को अनदेखा करता है जब यह फोरच लूप के दौरान मेरी सरणी के माध्यम से गणना करने का प्रयास करता है।

धन्यवाद

उत्तर

107

आप इस तरह के ArrayList के बजाय List<MyObject> के रूप में एक सामान्य संग्रह का उपयोग करने के लिए चुनते हैं, तो आप पाएंगे कि List<MyObject> दोनों सामान्य और गैर सामान्य प्रगणक है कि आप उपयोग कर सकते हैं प्रदान करेगा।

using System.Collections; 

class MyObjects : IEnumerable<MyObject> 
{ 
    List<MyObject> mylist = new List<MyObject>(); 

    public MyObject this[int index] 
    { 
     get { return mylist[index]; } 
     set { mylist.Insert(index, value); } 
    } 

    public IEnumerator<MyObject> GetEnumerator() 
    { 
     return mylist.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 
+0

गैर-सामान्य कार्यान्वयन में, 'this.GetEnumerator() 'को वापस करने और बस' GetEnumerator()' को वापस करने के बीच कोई अंतर है? –

+0

@TannerSwett कोई फर्क नहीं पड़ता। –

20

आप इसे मैन्युअल रूप से क्यों करते हैं? yield return इटरेटर को संभालने की पूरी प्रक्रिया को स्वचालित करता है। (मैंने इसके बारे में on my blog भी लिखा, जिसमें संकलक उत्पन्न कोड पर एक नज़र शामिल है)।

यदि आप वास्तव में इसे स्वयं करना चाहते हैं, तो आपको भी एक सामान्य गणनाकर्ता वापस करना होगा। आप गैर-जेनेरिक के बाद से ArrayList का उपयोग करने में सक्षम नहीं होंगे। इसे इसके बजाय List<MyObject> पर बदलें। यह निश्चित रूप से मानता है कि आपके संग्रह में केवल MyObject (या व्युत्पन्न प्रकार) के प्रकार हैं। एक List<MyObject> में

+2

+1, यह ध्यान दिया जाना चाहिए कि पसंदीदा पैटर्न सामान्य इंटरफ़ेस को लागू करना और स्पष्ट रूप से गैर-जेनेरिक इंटरफ़ेस को कार्यान्वित करना है। उधार वापसी जेनेरिक इंटरफ़ेस का सबसे प्राकृतिक समाधान है। – user7116

+4

जब तक ओपी गणक में कुछ प्रसंस्करण नहीं कर रहा है, उपज रिटर्न का उपयोग करके बस किसी अन्य राज्य मशीन के ऊपरी हिस्से को जोड़ता है। ओपी को अंतर्निहित जेनेरिक संग्रह द्वारा प्रदान किए गए एक गणक को वापस करना चाहिए। –

+0

@Monroe थॉमस: आप सही हैं। 'उपज वापसी' के बारे में लिखने से पहले मैंने प्रश्न को बहुत सावधानी से नहीं पढ़ा। मैंने गलत तरीके से माना कि कुछ कस्टम प्रसंस्करण थे। –

38

आप शायद नहीं है एक स्पष्टIEnumerable<T> के कार्यान्वयन (जो कि तुम क्या दिखाया है) चाहते हैं।

सामान्य पैटर्न IEnumerable की स्पष्ट कार्यान्वयन में IEnumerable<T> के GetEnumerator उपयोग करने के लिए है:

class FooCollection : IEnumerable<Foo>, IEnumerable 
{ 
    SomeCollection<Foo> foos; 

    // Explicit for IEnumerable because weakly typed collections are Bad 
    System.Collections.IEnumerator IEnumerable.GetEnumerator() 
    { 
     // uses the strongly typed IEnumerable<T> implementation 
     return this.GetEnumerator(); 
    } 

    // Normal implementation for IEnumerable<T> 
    IEnumerator<Foo> GetEnumerator() 
    { 
     foreach (Foo foo in this.foos) 
     { 
      yield return foo; 
      //nb: if SomeCollection is not strongly-typed use a cast: 
      // yield return (Foo)foo; 
      // Or better yet, switch to an internal collection which is 
      // strongly-typed. Such as List<T> or T[], your choice. 
     } 

     // or, as pointed out: return this.foos.GetEnumerator(); 
    } 
} 
+1

यह एक अच्छा समाधान है यदि कुछ कोलेक्शन पहले से ही IENumerable लागू नहीं करता है, या यदि आपको गणना अनुक्रम में वापस आने से पहले प्रत्येक तत्व पर अन्य प्रसंस्करण को बदलने या करने की आवश्यकता है। यदि इनमें से कोई भी स्थिति सत्य नहीं है, तो शायद यह वापस करने के लिए शायद अधिक कुशल है .foos.GetEnumerator(); –

+0

@Monroe थॉमस: सहमत हुए। कोई संकेत नहीं है कि ओपी किस संग्रह का उपयोग कर रहा है। – user7116

+4

अच्छा बिंदु। लेकिन 'IENumerable' को लागू करना अनावश्यक है (' IENumerable 'पहले से ही विरासत में मिला है)। – rsenna

3

आप जेनरिक, उपयोग ArrayList के बजाय सूची के साथ काम करते हैं। सूची में आपको वास्तव में GetEnumerator विधि की आवश्यकता है।

List<MyObject> myList = new List<MyObject>(); 
संबंधित मुद्दे