Not Rocket Science

A simple Even/Odd Cycler for .net

If you want a table with different CSS Styles for even/odd rows, that is reasonably easy, usually you have code like this:

bool evenRow = true;
foreach (var item in someList)
{
  evenRow = !evenRow;
  SomeTable.Rows.Add(SomeFunctionThatReturnsATableRow(item,evenRow?"evenRow":"oddRow"));
}

So we have a bool that we switch on every iteration and then we derive the CSS Class Name from that. If you do that in one place, it's okay, but if you have to do that in many places, it can become quite a bit tedious. Sure, if you happen to use a for-loop you can just use index % 2 == 0 to find out if you are on an even row, but I instead created a class:

public class EvenOddCycler
{
    private readonly string _oddClassName;
    private readonly string _evenClassName;
    private int _numCycles;

    public EvenOddCycler() : this("evenRow","oddRow"){}

    public EvenOddCycler(string evenClassName, string oddClassName)
    {
        _evenClassName = evenClassName;
        _oddClassName = oddClassName;
        _numCycles = 0;
    }

    public string Cycle()
    {
        _numCycles++;
        return IsCurrentlyEven ? _evenClassName : _oddClassName;
    }

    public void Reset()
    {
        _numCycles = 0;
    }

    public bool IsCurrentlyEven
    {
        get { return (_numCycles % 2 == 0); }
    }
}

Really simple stuff here: The constructor takes two strings, one for even and for odd. It has a Cycle function that increases a counter and returns one of the two strings. Also included a Reset() function to re-use the cycler in case you have more than one table on a page.

The usage looks like this:

var cycler = new EvenOddCycler();
foreach (var item in someList)
{
    SomeTable.Rows.Add(SomeFunctionThatReturnsATableRow(item,cycler.Cycle()));
}

What did we gain?

Granted. it's a small thing, but every little thing I don't have to worry about is good.

This is not Thread-safe because I see no scenario where you would share one cycler. Making it Thread-safe is a simple matter of adding a lock object and locking all three method bodies though.