Indexer Example
Let's look at some places where indexers make the most sense. I'll start with the list box example I've already used. As mentioned, from a conceptual standpoint, a list box is simply a list, or an array of strings to be displayed. In the following example, I've declared a class called MyListBox that contains an indexer to set and retrieve strings through an ArrayList object. (The ArrayList class is a .NET Framework class used to store a collection of objects.) -
using System;
using System.Collections;
class MyListBox
{
protected ArrayList data = new ArrayList();
public object this[int idx]
{
get
{
if (idx > -1 && idx < data.Count)
{
return (data[idx]);
}
else
{
// Possibly throw an exception here.
return null;
}
}
set
{
if (idx > -1 && idx < data.Count)
{
data[idx] = value;
}
else if (idx == data.Count)
{
data.Add(value);
}
else
{
// Possibly throw an exception here.
}
}
}
}
class Indexers1App
{
public static void Main()
{
MyListBox lbx = new MyListBox();
lbx[0] = "foo";
lbx[1] = "bar";
lbx[2] = "baz";
Console.WriteLine("{0} {1} {2}",
lbx[0], lbx[1], lbx[2]);
}
}
Notice in this example that I check for out-of-bounds errors in the indexing of the data. This is not technically tied to indexers because, as I mentioned, indexers pertain only to how the class's client can use the object as an array and have nothing to do with the internal representation of the data. However, when learning a new language feature, it helps to see practical usage of a feature rather than only its syntax. So, in both the indexer's getter and setter methods, I validate the index value being passed with the data being stored in the class's ArrayList member. I personally would probably choose to throw exceptions in the cases where the index value being passed can't be resolved. However, that's a personal choice-your error handling might differ. The point is that you need to indicate failure to the client in cases where an invalid index has been passed.