Ienumerator and ienumberator

Source: Internet
Author: User
Ienumerable only indicates that an object can be enumerated. The real work is completed by ienumerator's current, movenext, and reset. Why do we need two different interfaces for enumeration? The main reason is that the enumerated object will be called by multiple independent clients.
Introduction

This article discussesIEnumeratorAndIEnumerable
Interfaces in the. NET Framework. enumerators can be an incredibly
Powerful way of iterating through data. I had noticed that the msdn
Library didn't contain containers examples on the use of enumerators, and I
Felt that they are a too useful and powerful construction to have,
Without sufficient examples on their use.

Background

I first came authentication ss the conceptIteratorsFrom another object oriented language calledMagik. In that language it is possible to createITERMethod which can be used inforLoops in a similar way to the C #foreach. I wanted to be able to recreate some of the very powerful iterators I had used inMagikIn C #.

Iterators are useful in a variety of situations, e.g. When you want
To traverse a list in different ways, to be able to traverse
Contents of an object without exposing the internal representation, or
To provide a uniform way of traversing different aggregate structures.

Iterators are also very useful in situations where the amount
Data is not easily known at the start of the process. or where the data
Is coming from an outside, possibly asynchronous source-in this
Situation the use of an iterator can make, the method using
Iterator, considerably easier to read than, trying to code it into
Method itself, as all the logic for accessing the data is in
Iterator.

A further common usage that I have come into operation SS is
Deserialisation of a file. The iterator reads the file, callthe
Necessary factory methods and passes back objects that
It have been constructed based on data in the file.

Using the code

In the sample code, I have presented a small problem, enumerating
Through the cards in a standard deck of cards, with the jokers removed
And shown two ways in which an enumerator can be used in the. NET
Framework. First, usingwhileLoop accessingIEnumeratorBased object directly, and second, usingforeachLoop accessing the enumerator throughIEnumerableInterface.

This first enumerator class,suitsEnumerator, Will return each of the suits in a deck of cards.

First notice that the class usesIEnumeratorInterface. This is the base interface for all enumerators. Also note that to use this interface a referenceSystem.CollectionsNeeds to be encoded ded.

using System.Collections;public class suitsEnumerator : IEnumerator{

The following code sets up the class. As this
Is a very simple enumeration, I have placed all the values to be
Enumerated in a simple array. I have also initialisedm_nCurr
To the index of the current element. As enumerators are always
Initially pointed to just before the first element, this index is set
To-1.Reset()Method also sets the current index back to-1.

<span class="code-keyword"></span><pre class="Csharp" name="code">private static string[] suits = {"Hearts","Spades","Diamonds","Clubs"};private int m_nCurr = -1; public suitsEnumerator() {} public void Reset(){    m_nCurr = -1;}

TheMoveNext()Method, as the name implies,
Moves the Enumerator on to the next element. The return value indicates
Whether there is more data or not, and only when the thing being
Iterated over is exhausted will it returnfalse.

In this example the method only updates the index, but in other
Implementations, the enumerator class may have a member variable
Hold the current value if the lookup is complex.

<pre class="Csharp" name="code">public bool MoveNext(){    m_nCurr++;    if (m_nCurr &gt;= 4)        return false;    return true;}

Finally, there isCurrentProperty, which
Returns the current element. In this simple implementation a check is
Done to ensure the index is valid and the element at that index of
Array is returned. If the index is invalid then an exception is raised.

AsCurrentDoes not move the enumerator to the next element, it will always return the same value until eitherMoveNext()OrReset()Is called.

<span class="code-keyword"></span><pre class="Csharp" name="code">public object Current    {        get        {            if (m_nCurr&lt;0)                throw new InvalidOperationException();            if (m_nCurr&gt;3)                throw new InvalidOperationException();            return suits[m_nCurr];        }    }}

This is a very simple enumerator that can be used quite easily like the example below:

    <br><pre class="Csharp" name="code">Console.WriteLine("The suits are:");IEnumerator suits = new suitsEnumerator();while(suits.MoveNext())    Console.WriteLine(suits.Current);

In the provided code, there is another similarIEnumeratorDerived class calledcardValuesEnumeratorThat contains each possible value that a card may contain.

The second part of using enumerators in the. NET Framework isIEnumerableInterface. It provides the MethodGetEnumerator()WithIEnumeratorAs a return value. AlsoIEnumerableInterface can be found inSystem.CollectionsNamespace.

<span class="code-keyword"></span><pre class="Csharp" name="code">public class deckOfCards : IEnumerable{    ...    public IEnumerator GetEnumerator()    {        return new deckOfCardsEnumerator();    }    ...}

TheIEnumerableInterface is used on classes that are to be used withforeachStatement. the enumerator returned fromGetEnumerator()Method is used byforeachStatement.

<pre class="Csharp" name="code">Console.WriteLine("The deck of cards contains:");foreach(object card in new deckOfCards())    Console.WriteLine(card);

Normally the class inheriting fromIEnumerableWill not be the same class that inherits fromIEnumerator
Interface. It can do, however if it is then the class will not be
Thread safe, nor can you nest two or more iterations of the elements
The same class within each other. In otherwords the following will
Not be possible:

<span class="code-keyword"></span><pre class="Csharp" name="code">foreach(object obj1 in MyCollection){foreach(object obj2 in MyCollection){// Do something }}

If you can assert that there will only ever be one thread and never any nesting then the collection class withIEnumeratorInterface can also haveIEnumerableInterface withGetEnumerator()Method returningthis.

Exposing more than one enumerator

If you have a collection that cocould expose always ways of iterating through its contents you may like to create a numberIEnumeratorClasses. If you do thenGetEnumerator()On the collection class may become redundant unless you plan to return some default enumerator. In this case a class withIEnumerableAndIEnumerator
Interfaces can be created for each type of iteration so that the return
Value from the original collection class can be dropped directly into
foreachStatement.

The following code snipped shows an example of a class exposing extends enumerators that can be easily used inforeachStatement:

class SuperCollection{// All the ususal collection collection methods go herepublic ForwardEnumeration InAscendingOrder{get{return new ForwardEnumeration(/*some args*/);}}public ReverseEnumeration InDescendingOrder{get{return new ReverseEnumeration(/*some args*/);}}}class ForwardEnumeration : IEnumerator, IEnumerable{public ForwardEnumeration(/*some args*/){// Constructor Logic Here}// From the IEnumerable Interfacepublic IEnumerator GetEnumerator{return this;}/* Put IEnumerator logic here*/}class ReverseEnumeration : IEnumerator, IEnumerable{public ReverseEnumeration(/*some args*/){// Constructor logic here}// From the IEnumerable Interfacepublic IEnumerator GetEnumerator{return this;}/* Put IEnumerator logic here*/}/*Using the above classes*/public void SomeMethod(SuperCollection manyThings){foreach(object item in manyThings.InAscendingOrder){// Do something with the each object}foreach(object item in manyThings.InDescendingOrder){// Do something with each object}}

In many situations this may produce a cleaner construction than implementing it as two classes. e.g. WhereIEnumerableBased class only serves to construct and returnIEnumeratorBased class.

Personally, I wowould have also likedforeachTo permit the direct use ofIEnumeratorBased class, but if tried then the compiler will issue the error:

<pre class="Csharp" name="code">"foreach statement cannot operate on variables of type '<class name="">' because '<class name="">' does not contain a definition for 'GetEnumerator', or it is inaccessible."</class></class>
Points of interest

The biggest difference between the C # implementation, which is essential a form ofIteratorPattern as found in book mentioned below, andMagikImplementation is that, in Magik a method can be attributed asITER
Method, whereas in C # The Enumerator is a different class. in C # This
Can pose additional challenges, for one the iterator may need to have
Access to the internal structure of the thing being enumerated.

If you want to read more about iterators, and other design patterns,
I recommend the book mentioned below. It is an excellent reference
Design Patterns and also won a Software Development Magazine
Productivity Award.

If you have any questions please feel free to contact me.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.