views:

157

answers:

3

Is an indexer an extended version of a property?.

+3  A: 

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

class SampleCollection<T>
{
    // Declare an array to store the data elements.
    private T[] arr = new T[100];

    // Define the indexer, which will allow client code
    // to use [] notation on the class instance itself.
    // (See line 2 of code in Main below.)        
    public T this[int i]
    {
        get
        {
            // This indexer is very simple, and just returns or sets
            // the corresponding element from the internal array.
            return arr[i];
        }
        set
        {
            arr[i] = value;
        }
    }
}

// This class shows how client code uses the indexer.
class Program
{
    static void Main(string[] args)
    {
        // Declare an instance of the SampleCollection type.
        SampleCollection<string> stringCollection = new SampleCollection<string>();

        // Use [] notation on the type.
        stringCollection[0] = "Hello, World";
        System.Console.WriteLine(stringCollection[0]);
    }
}

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

Robert Harvey
+1  A: 

Indexers are a second layer of syntactic sugar. With properties, get and set are transformed into method calls, those methods prefixed with get_/set_. In the case of indexers, indexers transformed into the method Item(). With any indexer argument being the first arguments of the methods. Also, get_/set_ is prefixed to the methods.

For those who prefer examples:

string foo;
public string Foo {
    get {
        return foo;
    }
    set {
        foo = value;
    }
}
// becomes
string foo;
public string get_Foo() {
    return foo;
}
public void set_Foo(string value) {
    foo = value;
}

And here what happens with indexers:

string[] backingFoo;
public string this[int index] {
    get {
        return backingFoo[index];
    }
    set {
        backingFoo[index] = value;
    }
}
// becomes
string[] backingFoo;
public string get_Foo(int index) {
    return backingFoo[index];
}
public void set_Foo(int index, string value) {
    backingFoo[index] = value;
}
Dykam
+2  A: 

It depends on the viewpoint, really.

As far as C# is concerned, they are two orthogonal concepts. A class may have zero or more properties, and it may also have zero or more indexers. Properties are distinguished by their names, and indexers are overloaded by types of their arguments (similar to methods). They are similar in that either can have a gettor, a settor, or both, and in that assignment operators (including complex ones, such as +=) know how to handle them.

From CLS (and VB) perspective, there isn't such a thing as an indexer. There are only properties, and some of them are indexed, while others are not. An indexed property is the one where you have to provide additional values aside from the receiver itself to read the value, and receiver and new value to write the value - additional values are indices. There is also the concept of a "default property" - only one group of properties (all with the same name, but different index types) can be default.

From CLR perspective, a property by itself is just a name with a type and a bunch of methods associated with it; it doesn't really have any meaning on its own. It just shows where to find the methods when looking for accessors for the property of that name. There is no notion of default properties.

Now to reconcile those three things...

By CLS convention, plain properties are represented on CLR level by a property associated with methods with corresponding signatures, one for getter and one for setter. For a property Foo of type T, they would be:

T get_Foo();
void set_Foo(T);

And for an indexed property with indices of types I1, I2, ...:

T get_Foo(I1, I2, ...);
void set_Foo(I1, I2, ..., T);

To represent a default property, DefaultMemberAttribute is used to specify the name of that property.

C# reconciles its view with that of CLS by representing indexers as indexed properties. By default it uses the name Item for all such properties, but you can use IndexerNameAttribute to force it to name the property differently. It will also stick a DefaultMemberAttribute on the class with the indexer for that property, so it's seen as default property in VB (and other CLS-compliant languages that show indexed properties as such).

When consuming classes written in other languages, C# looks for DefaultMemberAttribute. If it's present, then indexed property referenced by it shows up as indexer on that class from C#. Indexed properties that aren't default are only accessible from C# by calling their accessor methods (get_Foo and set_Foo) directly - though this will change in C# 4 for COM-imported interfaces.

Pavel Minaev