[Translation] enumerators in C #

Source: Internet
Author: User
Source: http://www.ondotnet.com/pub/a/dotnet/2004/06/07/liberty.html
PDF browse: http://www.tracefact.net/Document/Iterators-In-CSharp.pdf

Enumerator Glossary in C #

Iterator: enumerator

If you are creating a class with the same performance and behavior as a set, it is convenient to allow users of the class to use the foreach statement to enumerate the members in the set. This is easier to implement than C #2.0 in C #1.1. For demonstration, we first add enumeration for a simple set in C #1.1, then we modify this example and use the new C #2.0 enumeration construction method.

We will start with creating a simple list box, which will contain an array of 8 strings and an integer that records how many strings have been added to the array. The constructor initializes the array and fills it with the passed parameters.

Public ListBox (Params string [] initialstrings)
{
Strings = new string [8];

Foreach (string s in initialstrings)
{
Strings [CTR ++] = s;
}
}

In addition, The ListBox class also requires an add method (to add a string) and a method to return the number of strings in the array.

Public void add (string thestring)
{
Strings [CTR] = thestring;
CTR ++;
}

Public int getnumentries ()
{
Return CTR;
}

 

Note:In actual development, arraylist is usually used instead of an array of fixed sizes. HereProgramIn a simple way, no array subscript out-of-bounds detection is performed.

In terms of feeling, ListBox is like a set. If you can use the foreach loop in the set to obtain all strings in ListBox, It is very convenient. In this case, you can writeCode:

ListBox lB = new ListBox ("A", "B", "C", "D", "E", "F", "g", "H ");
Foreach (string s in LB ){
Console. writeline (s );
}

However, the following error is returned:

"Iterator. ListBox" does not contain the public definition of "getenumerator". Therefore, the foreach statement cannot act on variables of the "iterator. ListBox" type.

To use the foreach statement, you must also implement the ienumerable interface.

This interface requires only one method: getenumerator. This method must return an object that implements the ienumerator interface. In addition, we need to return this object not only implements ienumerator, but also knows how to enumerate ListBox objects. You will need to create a listboxemunerator (described below ):

Note:Ienumerable and ienumerator are different interfaces. Do not confuse them.

 

Public ienumerator getenumerator ()
{
Return new listboxenumerator ();
}

Now, ListBox can use foreach loop:

ListBox LBT = new ListBox ("hello", "world ");

LBT. Add ("who ");
LBT. Add ("is ");
LBT. Add ("John ");
LBT. Add ("Galt ");

Foreach (string s in LBT)
{
Console. writeline ("value: {0}", S );
}

The ListBox is instantiated, two strings are initialized, and four strings are added. Foreach cyclically accepts the ListBox instance, iterates it, and returns strings in turn. The output is:

Hello
World
Who
Is
John
Galt

Implement the ienumerator Interface

Note that the listboxenumerator must not only implement the ienumerator interface, but also have some special knowledge about The ListBox class. In particular, it must obtain the string array of ListBox and traverse the strings it contains. The relationship between the ienumerable class and its related ienumerator class is a bit subtle. The best way to implement the ienumerator interface is to create a nested ienumerator class in the ienumerable class.

Public class ListBox: ienumerable
{
// Nested private listboxenumerator class implementation
Private class listboxenumerator: ienumerator
{
// Code implementation...
}
// Code of The ListBox class...
}

Note that the listboxenumerator must reference The ListBox class embedded in it. You can pass through the listboxenumerator constructor.

To implement the ienumerator interface, listboxenumerator requires two methods: movenext and reset. There is also an attribute: Current. These methods and attribute tasks create a State mechanism to ensure that you can know at any time which element in ListBox is the current element and obtain that element.

In this example, this state mechanism is completed by maintaining an index value indicating the current string, and, you can index the string set of the External Department class to return the current string. To achieve this goal, you need a member variable to save the reference to the external ListBox object and an integer to save the current index.

Private ListBox LBT;
Private int index;

The index is set to-1 each time the reset method is called.

Public void reset ()
{
Index =-1;
}

Every time movenext is called, the array check of the external class has reached the end. If so, the method returns false. If there are objects in the collection, the index is added and the method returns true.

Public bool movenext ()
{
Index ++;
If (index> = LBT. Strings. length)
{
Return false;
} Else
{
Return true;
}
}

Finally, if the movenext method returns true, the foreach loop will call the current attribute. The current attribute of listboxenumerator is used to index the set in the external class (ListBox) and return the found object (in this example, it is a string ). Note that an object is returned because the current attribute signature in the ienumerator interface is the same.

Public object current
{
Get {
Return (LBT [Index]);
}
}

In 1.1, all classes that want to iterate through the foreach loop must implement the ienumerable interface. Therefore, you must create a class that implements ienumerator. Worst of all, the values returned by enumerator are not of type security. Remember that the current attribute returns an object. It simply assumes that the value you return matches the expected value of the foreach loop.

C #2.0 solutions

With C #2.0, these problems have melted like snow at the end of May. In version 2.0 of this example, I overwrite the list above and use two new features of C #2.0: generics and enumerators.

I will redefine the ListBox to implement ieumerable <string> as the start:

Public class ListBox: ienumerable <string>

In this way, make sure that this class can be used in the foreach loop and that the iteration value is of the string type.

Now, the entire nested class is removed from the previous example and the getenumerator method is replaced with the following code.

Public ienumerator <string> getenumerator ()
{
Foreach (string s in strings)
{
Yield return S;
}
}

The getenumerator method uses the new yield statement. The yield statement returns an expression. The yield statement only appears in the iteration block and returns the expected value of the foreach statement. That is, each call to getgetenumerator generates the Next string in the set. All status management is done for you!

You have done that. You do not need to implement your own enumerator for each type, and you do not need to create Nested classes. You have removed at least 30 lines of code and greatly simplified your code. The program continues to run as expected, but state management is no longer your task, and everything is done for you. Furthermore, the value returned by the enumerator must be of the string type. If you want to return other types, you can modify the ienumerable generic statement. The ienumerable generic statement will reflect the new type.

More about yield

As a description of the previous section, we should tell you: in fact, you can add more than one yield value in the yield statement block. In this way, the following statements are completely correct C # statements:

Public ienumerator getenumerator ()
{
Yield return "who ";
Yield return "is ";
Yield return "John Galt? ";
}

If the above Code is located in a class named Foo, you can write it like this:

Foreach (string s in new Foo ())
{
Console. Write (s );
}

The output result will be:

Who is John Galt?

If you stop and think about it now, these are what the previous Code has done. It traverses its own foreach loop and generates each string it finds.

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.