[C# Howto] How to Make Your Class Enumerable

I am a fan of “foreach“. If I do not need a counter, I always use a “foreach” statement.

In your shopping cart application, you want to declare 2 classes: Product and ProductList.        

pubic class Product
{
  public string Name { get; set; }

  public Product() { Name = "N/A"; }
  public Product(string n) { Name = n; }
}

Now you want to define the “Productlist” class, which

  • stores a list of Product objects
  • can add/remove a Product object
  • can access each Product object
  • can enumerate each Product object one by one in the foreach loop

 

1. Easiest way – Inherit from List<T>

The “System.Collections.Generic.List<T>” already implements all functionalities you want. If you like freeriding, why do you bother to create all of these again?

public class ProductList : List<Product>
{
}

Done! I mean it’s really done. You can do it everything now.

ProductList products = new ProductList();

products.Add(new Product("Toy"));
products.Add(new Product("Clothes"));
products.Add(new Product("House"));
products.Add(new Product("Furniture"));

products.RemoveAt(2);

foreach (Product p in products)
{
  System.Console.WriteLine(p.Name); // Prints Toy, Clothes, Furniture
}

 

2. DIY – I need MY OWN version !!!

In most cases, subclassing from the “List<T>” class suits your needs. But if you need to control every behavior as you want, you can implement your custom List class.

You have noticed that .NET framework heavily uses interfaces when it comes to define certain behaviors. Enumeration is not different. “IEnumerable” and “IEnumerator” are the key players now.

  • System.Collections.IEnumerable
  • System.Collections.IEnumerator
  • System.Collections.Generic.IEnumerable<T>
  • System.Collections.Generic.IEnumerator<T>
public interface IEnumerable
{
  IEnumerator GetEnumerator();
}
public interface IEnumerator
{
  Object Current { get; }
  public bool MoveNext();
  public void Reset();
}
public interface IEnumerable<T> : IEnumerable
{
  IEnumerator<T> GetEnumerator();
  IEnumerable.IEnumerator GetEnumerator();
}
public interface IEnumerator<T> : IDisposable, IEnumerator
{
  T Current { get; }
  Object IEnumerator.Current { get; }
  public bool MoveNext();
  public void Reset();
}

I am going to explain only the generic versions here. If you understand them, it’s easy to use non-generic versions.

 

3. Implementing “IEnumerator” interface

Your custom class will implement the “IEnumerable” interface. But the only thing “IEnumerable” interface does returns any object that implements the “IEnumerator” interface.

Therefore you need to create a class that implements the “IEnumerator” interface.

If you use an array or any collection types as an internal storage, you can just use their default implementation of the “IEnumerable” interface. Or, you can define your custom Enumerator class.

 

4. Implementing “IEnumerable” interface

In the “GetEnumerator()” method, create an enumerator object or get your inner storage’s enumerator object.

public class ProductList : IEnumerable<Product>
{
  public List<Product> Items { get; set; }

  public ProductList()
  {
    Items = new List<Product>();
  }

  // IEnumerable<Product> Members
  public IEnumerator<Product> GetEnumerator()
  {
    return Items.GetEnumerator();
  }

  //IEnumerable Members
  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  {
    throw new NotImplementedException();
  }
}
ProductList products = new ProductList();

products.Items.Add(new Product("Toy"));
products.Items.Add(new Product("Clothes"));
products.Items.Add(new Product("House"));
products.Items.Add(new Product("Furniture"));

products.Items.RemoveAt(2);

foreach (Product p in products)
{
  System.Console.WriteLine(p.Name);
}

 

5. Building Iterator with the yield Keyword

To create an Enumerator is quite a lot of work. C# provides you with a simple construct to create your own enumerator without relying on pre-existing implementations.

In the “GetEnumerator()” method, you can return an element as the order you want by using the “yield” keyword.

public class ProductList : IEnumerable<Product>
{
  private Product[] items = new Product[10];

  public Product GetProductAtIndex(int index)
  {
    return items[index];
  }
  public void SetProductAtIndex(Product p, int index)
  {
    items[index] = p;
  }

  // IEnumerable<Product> Members
  public IEnumerator<Product> GetEnumerator()
  {
    foreach (Product p in items)
    {
      if ((p != null) && (p.Name != "House"))
      {
        yield return p;
      }
    }
  }

  //IEnumerable Members
  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  {
    return items.GetEnumerator();
  }
}
ProductList products = new ProductList();

products.SetProductAtIndex(new Product("Toy"),0);
products.SetProductAtIndex(new Product("Clothes"),1);
products.SetProductAtIndex(new Product("House"),2);
products.SetProductAtIndex(new Product("Furniture"),3);

foreach (Product p in products)
{
  System.Console.WriteLine(p.Name);
}

 

2 thoughts on “[C# Howto] How to Make Your Class Enumerable

  1. Thanks very much, this helped me immensely

    Thanks for also including the basics, ie “public class ProductList : List”

    For ages I’ve been thinking surely there’s a simple way to do this, yet this is the first time I’ve actually found it.

    Maybe it’s common knowledge so never gets mentioned? At least I know now 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s