Eliminate Unnecessary Code and Boost Performance with C# 2.0 Iterators

A design pattern is a solution that focuses on solving a particular problem or issue that commonly occurs. Design patterns are often associated with object-oriented programming, but they are not exclusive to it. Non-computing disciplines also have concepts similar to the design pattern, which is likely from where programmers borrowed the concept.

The existence of a design pattern does not imply that only one solution to the problem exists, nor does it mean it is the best solution in all cases. Patterns merely provide a best-practice approach to a particular problem as learned through the countless experiences of the programming community. There are often several variations of a pattern for a particular problem. It is up to each programmer to determine if and when to apply a particular pattern. Often, the programming environment in use can influence the choice of which pattern to apply. Not all programming environments and languages support all design patterns. What may be easy to create in one environment or language may be extremely difficult in another. (Find more examples of design patterns in the article titled Implement Common Creational Design Patterns".)

The idea behind the iterator design pattern is to expose a controlled manner to sequentially access the elements of an aggregate object without exposing its internal representation or design. Actions such as First(), Next(), CurrentItem(), and IsDone() are commonly exposed operations. Many of the System.Collection namespace classes implement the iterator pattern. Although they may use different names for the operations, they're basically the same. They expose a GetEnumerator() method, which returns the concrete iterator for the particular class. The iterator is used to traverse the structure.

Iterator Implementation Sample Code

The following sample code demonstrates an implementation of the iterator design pattern in the 1.0 and 1.1 versions of the Microsoft .NET Framework. It implements the IEnumerable interface in an outer class, which mandates the GetEnumerator method be implemented. This allows you to use it in foreach loops:

using System;
using System.Collections;

namespace CodeGuru.IteratorsSample
{
   class IteratorTest : IEnumerable
   {
      private ArrayList items = new ArrayList();

      public int Count
      {
         get { return items.Count; }
      }

      public object this[int index]
      {
         get { return items[index]; }
         set { items.Insert(index, value); }
      }

      public IEnumerator GetEnumerator()
      {
         return new IteratorSampleEnumerator(this);
      }

      private class IteratorSampleEnumerator : IEnumerator
      {
         IteratorTest aggregate = null;
         int index = -1;

         public IteratorSampleEnumerator(IteratorTest aggregate)
         {
            this.aggregate = aggregate;
         }

         public virtual object Current
         {
            get { return this.aggregate[index]; }
         }

         public virtual bool MoveNext()
         {
            index++;
            if (index >= this.aggregate.Count)
            {
               return false;
            }
            else
            {
               return true;
            }
         }

         public virtual void Reset()
         {
            index = -1;
         }
      }
   }

   class Program
   {
      static void Main(string[] args)
      {
         // Create an iterator and add sample data
         IteratorTest tests = new IteratorTest();
         tests[0] = "Test 1";
         tests[1] = "Test 2";
         tests[2] = "Test 3";
         tests[3] = "Test 4";
         tests[4] = "Test 5";

         foreach (object test in tests)
         {
            Console.WriteLine(test);
         }

         // Wait for the user so we can see output
         Console.ReadLine();
      }
   }
}

The sample output from the application will look something like this:

Test 1
Test 2
Test 3
Test 4
Test 5

To return an IEnumerator instance, you need another class that has intimate knowledge of your class and can iterate through the internal aggregate implementation.

Eliminate Unnecessary Code and Boost Performance with C# 2.0 Iterators

C# 2.0 Iterators

As you may have noticed in the example, the iterator design pattern isn't overly difficult to implement. However, those of you who have read many of my prior articles know that I'm all about eliminating unnecessary code and performance overhead. Hence, the prior implementation has both unnecessary code and performance overhead. If the implementation involves value types, boxing and unboxing get involved, which leads to the performance overhead. The unnecessary code results from the iterator needing in-depth knowledge of the aggregate class. With C# 2.0, you can rely on generics and the compiler to help reduce the amount of code and performance impact. A new yield statement appears only inside an iterator block. Each call to GetEnumerator will yield the next value in the collection, and all of the state management is handled.

C# 2.0 Iterator Implementation Sample Code

The following sample code removes the nested class from the previous example. It replaced the entire GetEnumerator method to use the yield statement. Additionally, it includes the use of generics so you can apply the example to any type:

using System;
using System.Collections;
using System.Collections.Generic;

namespace CodeGuru.IteratorsSample
{
   class IteratorTest2<T> : IEnumerable
   {
      private ArrayList items = new ArrayList();

      public int Count
      {
         get { return items.Count; }
      }

      public T this[int index]
      {
         get { return (T)items[index]; }
         set { items.Insert(index, value); }
      }

      public IEnumerator GetEnumerator()
      {
         foreach (T item in this.items)
         {
            yield return item;
         }
      }
   }

   class Program
   {
      static void Main(string[] args)
      {
         // Create an iterator and add sample data
         IteratorTest2<string> tests = new IteratorTest2<string>();
         tests[0] = "Test 1";
         tests[1] = "Test 2";
         tests[2] = "Test 3";
         tests[3] = "Test 4";
         tests[4] = "Test 5";

         foreach (string test in tests)
         {
            Console.WriteLine(test);
         }

         // Wait for the user so we can see output
         Console.ReadLine();
      }
   }
}

The sample output from the application will look just like it did before:

Test 1
Test 2
Test 3
Test 4
Test 5

There is less code involved in the overall solution and the performance is improved.

Future Columns

The topic of the next column has yet to be determined. If you have something in particular that you would like to see explained, please e-mail me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer (MCSD, MCSE, MCDBA) is a senior architect of .NET applications for large and mid-sized organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design, and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the second year in a row. You can reach Mark at mstrawmyer@crowechizek.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds