Now that you know how the for-in loop works, you should have no problems implementing the same functionality in a C# class.
To see how to add enumeration support to a custom C# class, we first need to create a class, in this case a Library class that will only contain five books. Each book in the library is a structure (Book structure) that has three public fields: Author, PageCount, and Title.
To declare a structure (record) in C#, you have to use the reserved word struct, followed by the structure's name, and list the structure's fields in its block. The fields you want to use from the outside world need to be marked as public, just like fields in a class.
Here's the Book structure used by the Library class:
using System; namespace Wordware.ForEachSupport { struct Book { public string Author; public int PageCount; public string Title; } }
The Library class is a very simple class that has methods for changing and displaying book data. The entire Library class is displayed in Listing 30-5.
Listing 30-5: The Library class
class Library { public int Count = 5; private Book[] books = new Book[5]; /* this method displays a book */ public void Show(Book aBook) { if(aBook.Title == null) return; Console.WriteLine("Title: {0}", aBook.Title); Console.WriteLine("Author: {0}", aBook.Author); Console.WriteLine("Page Count: {0}", aBook.PageCount); Console.WriteLine(); } /* this method can be used to modify a book */ public void Set(int bookID, string title, string author, int pageCount) { if((bookID >= 0) && (bookID <= books.Length - 1)) { books[bookID].Author = author; books[bookID].Title = title; books[bookID].PageCount = pageCount; } } /* this method is used by the LibraryEnumerator class */ public Book GetBook(int bookID) { return books[bookID]; } [STAThread] static void Main(string[] args) { Library library = new Library(); library.Set(0, "The Art of War", "Sun Tzu", 260); library.Set(1, "Amber Chronicles", "Roger Zelazny", 1200); } }
To loop through the books stored in a Library object with the foreach statement, we need to create the LibraryEnumerator class. In C#, we also have to link the main class with the enumerator class (in the constructor), create the public function MoveNext() to advance to the next element in the collection, create the public property Current to return the currently selected element, and create a Reset method that resets the loop to its initial position (–1). We also have to create the GetEnumerator() public method in the main class to create and return a new instance of the enumerator class.
But before we create the enumerator class, we need to see how to create a property in a C# class. Properties in C# are implemented with the following syntax:
access_modifier data_type PropertyName { get { // place code that reads the property value here } set { // place code that changes the property value here } }
The above syntax is used to create properties that can be read from and written to. If you want to (or have to) create a read-only property, you can create it by simply not implementing the set part of the property.
Here's what the Current read-only property of the LibraryEnumerator class looks like:
// public read-only property that returns a Book structure // lib is a Library instance public Book Current { get { return lib.GetBook(index); } }
Listing 30-6 shows the entire LibraryEnumerator class, the GetEnumerator() public method of the Library class, and the updated Main() method that uses the foreach statement to loop through the books stored in a Library instance.
Listing 30-6: The LibraryEnumerator class
using System; namespace Wordware.ForEachSupport { class Library { public LibraryEnumerator GetEnumerator() { return new LibraryEnumerator(this); } [STAThread] static void Main(string[] args) { Library library = new Library(); library.Set(0, "The Art of War", "Sun Tzu", 260); library.Set(1, "Amber Chronicles", "Roger Zelazny", 1200); foreach(Book book in library) { library.Show(book); } Console.WriteLine("Press any key to continue..."); Console.ReadLine(); } } // ----------------------------------------------------------------------- class LibraryEnumerator { private Library lib; private int index = -1; /* the constructor */ public LibraryEnumerator(Library library) { lib = library; } public bool MoveNext() { bool Result = index < lib.Count - 1; if(Result == true) index++; return Result; } public Book Current { get { return lib.GetBook(index); } } public void Reset() { index = -1; } } // LibraryEnumerator class } // namespace