Stupid C# tricks: Working with indexers

Properties 101
If you've done any programming in
VB6, you'll be familiar with property methods—special class members that allow
controlled access to a private class field. In C#, you have two kinds of
properties: get, which allows you to return the value of a private field,
and set, which allows you to set the value of a private field. As a
simple example, consider the code below, which creates a FirstName
property to control access to the private class member firstname:
class Person {
private string firstname;
public string FirstName {
get {return firstname;}
set {firstname = value;}
}
}
That property declaration would allow you to write code like this:
Person p = new Person();
p.FirstName = "Lamont";
Console.WriteLine (p.FirstName);
As you can see, a property declaration looks a lot like a field declaration, except that it's declared with two special members, called accessors in Microsoft parlance. The get accessor is called when the property is invoked on the right-hand side of an expression or used as a parameter to another routine. The set accessor is called when the property is invoked on the left-hand side of an expression and sets the value of its associated private field via the implicitly passed value parameter. You'd create a read-only property by omitting the set accessor, which would cause any attempts to set the property to generate compiler errors.
Using indexers for fun and profit
So why did I launch myself on that tangent? Because a class indexer works almost exactly like a property and looks very similar when you examine the code. Here's a sample class with an indexer that returns a string:
class Sample {
public string this [int index] {
get {return "You passed " + index; }
)
}
Notice that the property name is this, which refers back to the current instance of the class, and that the parameter list is enclosed in square brackets instead of parentheses. Also, this is a read-only indexer. To make it read/write, I'd have to add a set accessor. When defining an indexer, you are not limited to a single parameter. Indexer parameters may be of any type, although int usually makes the most sense. It's also possible to have more than one indexer in the same class (overloading)—more on that later.
Having defined Sample in this way, we can use the indexer as a sort of default property, like so:
Sample s = new Sample();
Console.WriteLine(s[55]);
Properties vs. indexers
There are a few differences between properties and indexers. Essentially, they boil down to the following:
Advanced tricks: Interfaces
When array-like behavior is desired for an implementer, you can define indexers
for interfaces. In fact, the IList and IDictionary collection
interfaces both declare an indexer to provide access to the items they're
storing.
When declaring an indexer for an interface, remember that the declaration just serves to indicate the existence of the indexer. You need only provide the appropriate accessors and should not include a scope modifier. The following is an example of an indexer declared as part of an interface appropriately named IImplementMe:
interface IImplementMe {
string this[int index]
{
get;
set;
}
An implementing class would have to provide the implementations for both the get and set accessors for IImplementMe's indexer.
That'll about do it for now. You should have a strong enough understanding of indexers to play with them on your own. Have fun.