Someone asked me about this, so I decided to write up the answer here in case other folks are interested.

 

Indexers are pretty well documented on the web; I’ll quote some here.

 

http://www.csharphelp.com/archives/archive140.html

C# introduces a new concept known as Indexers which are used for treating an object as an array. The indexers are usually known as smart arrays in C# community. Defining a C# indexer is much like defining properties. We can say that an indexer is a member that enables an object to be indexed in the same way as an array.

 <modifier> <return type> this [argument list]
 {
  get
  {
   // Get codes goes here
  }
  set
  {
   // Set codes goes here
  }
 }

 

I don’t usually know them as “smart arrays” which must mean I’m not really part of the C# community.  But I’m trying!

 

Or the official source: http://msdn.microsoft.com/library/en-us/csref/html/vclrfindexedpropertiespg.asp

Indexers allow you to index a class or a struct instance in the same way as an array.

Hmm, that’s better.  Let’s have an example:

 

class MyCollection<T>

{

      T this[uint i]

      {

            get

            {

                  return //...

            }

      }

}

 

class C

{

      static void Main(string[] args)

      {

            MyCollection<string> someStrings = ...;

            // here we index into the object like we would into an array

            Console.WriteLine(someStrings[1]);

      }

}

 

 

On the language tools side, indexers are a little funky.  They look a lot like methods (parameter list, return type, accessibility) and a lot like properties (separate ‘get’ and ‘set’ accessors) and a bit different from both (no name).

 

 

So, what are named indexers? 

 

Well, regular indexers don’t have a name, you just use them.  But what if there are two different ways to index in to your object?  You could overload, if that makes sense for your domain:

 

      T this[uint i] { get { /*...*/ } }

      T this[string s] { get { /*...*/ } }

 

Or you could use my “named indexer pattern” to create the appearance of a named indexer.  Here’s an example with 2 named indexers to give some context. 

 

class Car

{

      //

      // wheels

      //

      object[] wheels;

 

      public IIndexer<object, uint>.Get Wheels { get { return new WheelsHelper(this); } }

 

      public struct WheelsHelper : IIndexer<object, uint>.Get

      {

            readonly Car _outer;

 

            public WheelsHelper(Car mc) { this._outer = mc; }

 

            object IIndexer<object, uint>.Get.this[uint index] { get { return this._outer.wheels[index]; } }

      }

 

      //

      // seats

      //

      object[] seats;

 

      public SeatsHelper Seats { get { return new SeatsHelper(this); } }

 

      public struct SeatsHelper

      {

            readonly Car _outer;

 

            public SeatsHelper(Car mc) { this._outer = mc; }

 

            public object this[int index] { get { return this._outer.seats[index]; } }

      }

}

 

Now you can just write ‘car.Seats[1]’ and it works.

 

BTW, to compile this code, you’ll also need this code, which I just made up.  It’s an experiment; not sure if I like it or not.

 

static class IIndexer<T, I>

{

      public interface Get { T this[I index] { get;} }

      public interface Set { T this[I index] { set;} }

      public interface Both : Get, Set { }

}