IEnumerable and IEnumerator

जब हम हमारा स्वयं का Collection Create करते हैं, तो उस Collection के विभिन्न Elements को Traverse करने के लिए हम सामान्‍यत: foreach Looping Construct को Use करना चाहते हैं। जबकि Traversing करने का दूसरा तरीका Enumerator होता है।

Enumerator एक ऐसा Object होता है जो या तो Non-Generic IEnumerator Interface को Implement करता है या फिर Generic IEnumerator<T> को। दोनों ही Versions के IEnumerator Interface में Current नाम का एक Read-Only Property होता है, जो कि Collection के Current Item को Point करता है।

IEnumerator Interface में MoveNext() Reset() नाम के दो Methods को Define किया गया है, जिनमें MoveNext() नाम का Method Enumerator की Current Position को Move करता है ताकि अगले Collection Element को Traverse किया जा सके। लेकिन यदि Collection में Traversing के लिए कोई Next Element Exist न हो, तो ये Method false Return करता है, जबकि यदि हम Enumeration को फिर से शुरू से Run करना चाहें यानी यदि हम Collection में फिर से First Element से Traversing शुरू करना चाहें, तो हमें Reset() Method को Invoke करना होता है। इस Method को Invoke करने के बाद हम फिर से MoveNext() Method द्वारा Collection की शुरूआत से Traversing कर सकते हैं।

जब हम Enumerators का प्रयोग करते हैं, तब हम किसी Enumerator के माध्‍यम से Collection के किसी Item के मान को Change नहीं कर सकते, क्योंकि Collections हमेंशा Read-Only होते हैं और यदि हम Enumeration के दौरान Collection में किसी तरह का Change करते हैं, तो Enumerator Invalidate हो जाता है।

इससे पहले कि हम किसी Collection को Enumerator के माध्‍यम से Access करें, हमें Enumerator को Retrieve करना पडता है। .NET Framework में पहले से Defined सभी Collection Classes GetEnumerator() नाम का एक Method Provide करती हैं, क्योंकि इन सभी Classes में IEnumerable Interface को Implement किया गया होता है।

ये GetEnumerator() Method Current Collection के Starting Item का Enumerator Return करता है। इस Return होने वाले Enumerator के Reference को IEnumerator Reference Variable में Retrieve करके हम उस Collection के विभिन्न Items को One by One Access व Manipulate कर सकते हैं।

यानी किसी Collection के Items को Enumerator द्वारा One by One Access करने के लिए हम निम्न Steps Follow कर सकते हैं:

  • सबसे पहले हम Collection के GetEnumerator() Method को Call करके Collection के Starting Element का Enumerator Reference प्राप्त करते हैं।
  • फिर एक Loop Setup करते हैं, जिसमें MoveNext() Method को तब तक बार-बार Call किया जाता है, जब तक कि MoveNext() Method false Return नहीं कर देताए जो कि इस बात का Indication होता है कि अब Collection में Traverse करने के लिए एक भी Next Item Exist नहीं है।
  • Setup किए गए Loop के अन्दर हर Element को Current Property द्वारा Access किया जाता है।

Implementing IEnumerable and IEnumerator

किसी Collection के विभिन्न Elements पर Looping करने के लिए IEnumerator Method की तुलना में foreach Looping Construct सबसे बेहतर तरीका होता है। लेकिन जब हम हमारे किसी Class को Collection की तरह Define करते हैं और चाहते हैं कि उसके सभी Collection Elements को foreach Loop द्वारा Access किया जा सके, तो हमें उस Class में IEnumerator Interface को Implement करना जरूरी होता है। साथ ही हमें उसी Class में IEnumerable Interface को भी Implement करना जरूरी होता है।

अन्‍य शब्दों में कहें तो अपने किसी Class को Collection की तरह Use करते हुए उसके सभी Internal Objects को foreach Looping Construct द्वारा Accessible बनाने के लिए हमें उस Class में IEnumerableIEnumerator दोनों Interfaces को Implement करना जरूरी होता है।

IEnumerable IEnumerator नाम के Interfaces को .NET Framework में पहले से ही Define किया जा चुका है और ये दोनों ही हमें हमारे किसी User Defined Class या Structure के  Array के सभी Objects को foreach Loop द्वारा Access करने की सुविधा Provide करते हैं।

यानी जिस तरह से हम किसी Array के विभिन्न Elements को एक foreach Construct द्वारा One by One Access कर सकते हैं, उसी तरह से हमारी जिस Class में इन Interface को Implement करते हैं, उन Classes के Objects के Array के साथ भी हम foreach Looping Construct का समान तरीके से प्रयोग करके Array के सभी Objects को Access कर सकते हैं। जैसे:

	 int[] IntArray = {10, 20, 30, 40, 50};

	foreach(int i in IntArray)
		Console.WriteLine(i);

जैसाकि हम foreach Loop को देखकर समझ सकते हैं कि ये Loop IntArray के विभिन्न Elements पर Stored सभी Integer Values को One by One Screen पर Display करेगा।

जिस तरह से एक Array के लिए ये foreach Looping Construct काम कर रहा है, उसी तरह से हम किसी भी Custom Collection Class में IEnumerator IEnumerable Interfaces को Implement करके उस Class के Internal Objects को foreach Loop द्वारा One by One Access करने के लिए भी foreach Construct को Re-Specify कर सकते हैं। जैसे:

File Name: IEnumerableAndIEnumeratorInterface.cs
using System;
using System.Collections;

namespace CSharpInterface
{
    public class Watch
    {
        internal byte hour, minute;
        internal string name;
    }

    class WatchArray : IEnumerator, IEnumerable
    {
        int index = -1;
        Watch[] RoyalWatches = new Watch[4];

        //Collection Items
        public WatchArray()
        {
            RoyalWatches[0] = new Watch() { hour = 12, minute = 0, name = "HMT" };
            RoyalWatches[1] = new Watch() { hour = 10, minute = 10, name = "SONATA" };
            RoyalWatches[2] = new Watch() { hour = 5, minute = 40, name = "RADO" };
            RoyalWatches[3] = new Watch() { hour = 3, minute = 0, name = "TITAN" };
        }

        //Implementation of IEnumerable Interface's GetEnumerator() Method 
        public IEnumerator GetEnumerator()
        {
            return this;
        }

        //Implementation of IEnumerator Interface's GetEnumerator() Method 
        // Return the current object.
        public object Current
        {
            get
            {
                return RoyalWatches[index];
            }
        }

        // Advance to the next object.
        public bool MoveNext()
        {
            if (index == RoyalWatches.Length - 1)
            {
                Reset();			// reset enumerator at the end
                return false;
            }
            index++;

            return true;
        }

        // Reset the enumerator to the start.
        public void Reset()
        {
            index = -1;
        }
    }

    class UsingWatchArray
    {
        public static void Main(string[] args)
        {
            WatchArray Watches = new WatchArray();

            foreach (Watch x in Watches)
            {
                Console.WriteLine("Time of {0} - {1}:{2}", x.name, x.hour, x.minute);
            }
        }
    }
}

// Output:
   Time of HMT - 12:0
   Time of SONATA - 10:10
   Time of RADO - 5:40
   Time of TITAN - 3:0

इस Program में हमने जो WatchArray नाम की Class Define की है, इस प्रकार की Class को C# में Collection के नाम से जाना जाता है, क्योंकि इस Class में हम Watch Type के बहुत सारे Objects को एक List के रूप में Store व Manipulate कर रहे हैं।

जिस तरह से एक Primary Type के Array के विभिन्न Elements को foreach Loop द्वारा Access किया जाता है, ठीक उसी तरह से उपरोक्त Program में Defined WatchArray Collection के साथ foreach Loop तब तक Use नहीं किया जा सकताए जब तक कि हम WatchArray Class में IEnumerable Interface के GetEnumerator() Method को तथा IEnumerator Interface के MoveNext() Reset() Method तथा Current Property को Implement नहीं कर देते।

जब ये Program Run होता है, तो Main() Method में WatchArray Collection Type का watches नाम का एक Object Create किया जाता है और निम्नानुसार तरीके से foreach Loop में Specify किया जाता है:

            foreach (Watch x in Watches)
            {
                Console.WriteLine("Time of {0} - {1}:{2}", x.name, x.hour, x.minute);
            }

परिणामस्वरूप जब C# Compiler इस foreach Loop को Run करता है, तो निम्नानुसार तरीके से Defined IEnumerable Interface का GetEnumerator() Method Automatically Internally Execute हो जाता है:

        public IEnumerator GetEnumerator()
        {
            return this;
        }

ये GetEnumerator() Method Execute होते ही सभी RoyalWatches Collection के Current Item को Enumerator की तरह Return कर देता है जो कि WatchArray Collection में निम्नानुसार Statement के माध्‍यम से Index Number 0 के Item के रूप में Specified होता है:

RoyalWatches[0] = new Watch() { hour = 12, minute = 0, name = “HMT” };

जैसे ही GetEnumerator() Method, Collection के Current Item को Enumerator की तरह Return करता है, IEnumerator Interface का MoveNext() Method Execute हो जाता है और Current Property में Collection के अगले Item का Reference Set हो जाता है।

परिणामस्वरूप जब foreach Loop फिर से Execute होता है, तो इस बार फिर से GetEnumerator() Method Execute होता है, लेकिन इस बार Current Property में, Collection में निम्नानुसार Statement द्वारा Specified Index Number 1 पर स्थित Object का Pointer Set होता है:

RoyalWatches[1] = new Watch() { hour = 10, minute = 10, name = “SONATA” };

इसलिए इस बार ये Method इस नए Object की Information को Enumerator Item के रूप में Return करता है और फिर से MoveNext() Method को Invoke करके Current Property में तीसरे Item का Reference Set कर देता है और ये प्रक्रिया तब तक चलती रहती है, जब तक कि Collection के सभी Elements Traverse नहीं हो जाते।

जबकि यदि हम Traversing को फिर से शुरू करने के लिए foreach Loop को फिर से Use करते हैं, तो Current का मान फिर से Collection के First Element पर Set हो जाता है और सारी प्रक्रिया फिर से Follow होने लगती है तथा उपरोक्त Discussed सभी Steps फिर से Follow होने लगते हैं।

किसी Class में इन दोनों Interfaces को Implement करके हम C# को यही Information देते हैं कि जिस तरह से एक Primary Type के साथ foreach Loop को Use किया जाता है, Exactly उसी तरह से किसी User Defined Type के साथ foreach Loop को कैसे Use किया जा सकता है। .NET Framework में IEnumerator Interface को निम्नानुसार तरीके से Declare किया गया है:

	// This interface informs the caller that the object's subitems can be enumerated.
	public interface IEnumerable
	{
		IEnumerator GetEnumerator();
	}

जैसाकि इस Declaration में हम देख सकते हैं कि GetEnumerator() Method System .Collections.IEnumerator नाम के IEnumerator Type का एक Reference Return करता है, जिसमें Collection की शुरूआत की Information होती है।

इसलिए जिस Class में इस IEnumerator Interface को Implement किया गया होता है, उस Class के माध्‍यम से हम Collection के विभिन्न Elements की Traversing करने के लिए foreach Looping Construct को Setup कर सकते हैं।

IEnumerator Interface एक ऐसा Infrastructure Provide करता है, जो हमें किसी IEnumerable Compatible Container (Collection) (यानी जिस Class में IEnumerable Interface को Implement करते हुए GetEnumerator() Method को Define किया या है।)  के विभिन्न Internal Objects यानी Collection Items की Traversing करने की सुविधा Provide करता है। इस Interface को .NET Framework में निम्नानुसार Specify किया गया है:

	// This interface allows the caller to obtain a container's subitems.
	public interface IEnumerator
	{
		bool MoveNext (); 	// Advance the internal position of the cursor.
		object Current { get;} 	// Get the current item (read-only property).
		void Reset (); 		// Reset the cursor before the first member.
	}

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS