views:

337

answers:

10

Doing some code reading and stumbled upon this snippet that I haven't seen before:

public SomeClass {
  public someInterface this[String strParameter] {
    get {
      return SomeInternalMethod(strParameter);
    }
  }
}

It looks like it is called as follows:

SomeClass _someClass = new SomeClass();
SomeInterface returnedValue = _someClass["someString"];

I am interested in where this function would be appropriate or what the intent of writing in this style. For example why would this be preferred over simply calling the function?

+4  A: 

In many cases, the 'index' syntax makes a lot of sense. It is particularly useful if the SomeClass represents some sort of collection.

Erich
+3  A: 

It allows you to do associative array lookups (a.k.a. "dictionary style"), just as you mentioned in your question.

And that's the whole point. Some people like that, particularly people coming from languages that have it built in, like Python or PHP

Randolpho
A: 

It an implementation of the index operator [ ].

psychotik
A: 

It's an operator overload. Useful if you are writing a collection class for example where it would make sense to access it using array notation, e.g. collection[someIndex].

You could of course write a collection.GetElement(someIndex) function equivalent, but it's a style/readability thing.

Paolo
+3  A: 

The "this" keyword is an indexer

from http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx

"Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that their accessors take parameters."

Simon
What do you mean: the "this" keyword is an indexer?
spender
A: 

Well you could use this method in a key-value pair class.

I am not sure what the analogous class is in c#, but in c++ STL, there is the map class where you call the method with the SomeObject["key"] and it will return the "value" associated with that key.

zipcodeman
The analogous class in C# is System.Collections.Generic.Dictionary(except the Dictionary uses a hash lookup, while map orders the keys)
Andrew Shepherd
A: 

That's called an Indexer, they allow you to use List<>, ArrayList, Dictionary<> and all the other collections using an array syntax.

It's just syntactic sugar, but it gives some readability when used right.

AlbertEin
+15  A: 

See the language specification, section 10.9, which states:

An Indexer is a member that enables an object to be indexed in the same way as an array.

Indexers and properties are very similar in concept, but differ in the following ways:

  • A property is identified by its name, whereas an indexer is identified by its signature.
  • A property is accessed through a simple-name (§7.5.2) or a member-access (§7.5.4), whereas an indexer element is accessed through an element-access (§7.5.6.2).
  • A property can be a static member, whereas an indexer is always an instance member.
  • A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer.
  • A set accessor of a property corresponds to a method with a single parameter named value, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named value.
  • It is a compile-time error for an indexer accessor to declare a local variable with the same name as an indexer parameter.
  • In an overriding property declaration, the inherited property is accessed using the syntax base.P, where P is the property name. In an overriding indexer declaration, the inherited indexer is accessed using the syntax base[E], where E is a comma separated list of expressions.
Eric Lippert
I know I shouldn't hijack this, but maybe you could blog about why there are no Static Indexers? I was shocked when I saw that they don't exist, just because it's such a nice, shorthand way. (In before Jon brings up the good Encoding["UTF8"] Example :))
Michael Stum
I just checked the design notes archive and there is nothing in there justifying the decision to not have static indexers. I must therefore fall back on my usual explanation for why we don't have a feature: no one thought it was a good enough idea to spend the money on making it real. I imagine that this same explanation also explains why indexers cannot be generic.
Eric Lippert
Cool :) The nice thing about the "default" explanation is that it doesn't completely shut the door of this ever being possible. I have no idea how "heavy" this feature is (and I will not disqualify myself by saying "but it's only a small change!" without knowing how the compiler and CLR actually work), but it's better than "We didn't do it because of X, Y and Z that make it impossible to ever implement it".
Michael Stum
Great info - I didn't know it was called an indexer so I didn't know where to start to look for its definition. I guess I'm getting tripped up as to why the author uses a readonly indexer with a string parameter. If it were an int I'd get it as you could use it with loops, etc. Using a string parameter gives a dictionary type structure but it is readonly so it really feels like a method as you cannot pass it a value.
Michael Gattuso
+1  A: 

You may have already stumbled across something similar before:

var myList = new List<string>();
myList.Add("One");
myList.Add("Two");
myList.Add("Three");

for(int i = 0; i < myList.Count; i++) {
    string s = myList[i];
}

The indexer is the "primary key" of an object that implements a collection. It's just a shorthand way for writing a function like .GetValue(index) - syntactic sugar, if you want. But it also makes the intent clear.

Michael Stum
+4  A: 

It seems like a lot of the answers are focusing on what an indexer is, not why you would want to use one.

As far as I'm concerned, here is the motivation to use an indexer:

You are working on a class that has a collection of some sort, but you want the class to appear to users (consumers of the class) as if it is a collection.

The best example I can think of is the DataRow class in ADO.NET. If you want to get the value of the fifth cell of a DataRow, you can either use DataRow.Item[4] or DataRow[4]. The latter form is a convenient and logical shortcut, and it shows off pretty nicely why you'd want to use an indexer. To the user, the DataRow can be thought of as just collection of cells (even though it is really more than that), so it makes sense to be able to get and set cell values directly, without having to remember that you are actually getting/setting an Item.

Hope that helps.

DanM