Recipe6.2.Creating Custom Enumerators


Recipe 6.2. Creating Custom Enumerators

Problem

You need to add foreach support to a class, but the normal way of adding an iterator (i.e, implementing IEnumerable on a type and returning a reference to this IEnumerable from a member function) is not flexible enough. Instead of simply iterating from the first element to the last, you also need to iterate from the last to the first, and you need to be able to step over, or skip, a predefined number of elements on each iteration. You want to make all of these types of iterators available to your class.

Solution

The Container<T> class shown in Example 6-2 acts as a container for a private List<T> called internalList. Container is implemented so you can use it in a foreach loop to iterate through the private internalList.

Example 6-2. Creating custom iterators

 public class Container<T>  {     public Container() {}     private List<T> internalList = new List<T>();     public List<T> List     {         set {internalList = value;}     }     // This iterator iterates over each element from first to last.     public IEnumerator<T> GetEnumerator()     {         for (int index = 0; index < internalList.Count; index++)         {             yield return (internalList[index]);         }     }     // This iterator iterates over each element from last to first.     public IEnumerable<T> ReverseOrder     {         get         {             for (int index = internalList.Count - 1; index >= 0; index--)             {                 yield return (internalList[index]);             }         }     }     // This iterator iterates over each element from first to last stepping     // over a predefined number of elements.     public IEnumerable<T> ForwardOrderStep(int step)     {         for (int index = 0; index < internalList.Count; index += step)         {             yield return (internalList[index]);         }     }     // This iterator iterates over each element from last to first stepping     // over a predefined number of elements.     public IEnumerable<T> ReverseOrderStep(int step)     {         for (int index = internalList.Count - 1; index >= 0; index -= step)          {              yield return (internalList[index]);          }      } } 

Discussion

Iterators provide an easy method of moving from item to item within an object using the familiar foreach loop construct. The object can be an array, a collection, or some other type of container. This is similar to using a for loop to manually iterate over each item contained in an array. In fact, an iterator can be set up to use a for loop, or any other looping construct for that matter, as the mechanism for yielding each item in the object. In fact, you do not even have to use a looping construct. The following code is perfectly valid:

 public static IEnumerable<int> GetValues() {     yield return 10;     yield return 20;     yield return 30;     yield return 100; } 

With the foreach loop, you do not have to worry about moving the current element pointer to the beginning of the list or even about incrementing this pointer as you move through the list. In addition, you do not have to watch for the end of the list, since you cannot go beyond the bounds of the list. The best part about the foreach loop and iterators is that you do not have to know how to access the list of elements within its containerindeed, you do not even have to have access to the list of elements; the iterator member(s) implemented on the container do this for you.

The Container class contains a private List of items called internalList. There are four iterator members within this class:

 GetEnumerator ReverseOrder ForwardOrderStep ReverseOrderStep 

The GetEnumerator method is implemented to return an IEnumerable<T>. This method iterates over each element in the internalList from the first to the last element. This iterator, similar to the others, uses a for loop to yield each element in the internalList.

The ReverseOrder property implements an iterator in its get accessor (set accessors cannot be iterators). This iterator is very similar in design to the GetEnumerator method, except that the for loop works on the internalList in the reverse direction. Notice that even though this iterator is implemented as a property, there is no reason why it cannot be implemented as a method that takes no parameters.

The last two iterators, ForwardOrderStep and ReverseOrderStep, are similar in design to GetEnumerator and ReverseOrder, respectively. The main difference (besides the fact that ReverseOrder is a property) is that the for loop uses the step parameter to skip over the specified number of items in the internalList. Notice also that only the GetEnumerator method must return an IEnumerator<T> interface; the other three iterators must return IEnumerable<T> interfaces.

Using each of these iterators is extremely simple. To iterate over each element in the Container object from first to last, use the following code:

 Container<int> cntnr = new Container<int>();  //…Add data to cntnr here … foreach (int i in cntnr)  {      Console.WriteLine(i); }  

To iterate over each element in the Container object from last to first, use the following code:

 Container<int> cntnr = new Container<int>(); //…Add data to cntnr here … foreach (int i in cntnr.ReverseOrder) {     Console.WriteLine(i); } 

To iterate over each element in the Container object from first to last while skipping every other element, use the following code:

 Container<int> cntnr = new Container<int>(); //…Add data to cntnr here … foreach (int i in cntnr.ForwardOrderStep(2)) {     Console.WriteLine(i); } 

To iterate over each element in the Container object from last to first while skipping to every third element, use the following code:

 Container<int> cntnr = new Container<int>(); //…Add data to cntnr here … foreach (int i in cntnr.ReverseOrderStep(3)) {     Console.WriteLine(i); } 

In each of the last two examples, the iterator method accepts an integer value, step, that determines how many items will be skipped.

See Also

See the "Iterators," "yield," "IEnumerator Interface," and "IEnumerable Interface" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net