Indexer Insights
We all know that types, including interfaces can have a default property. Default properties are used as a short-hand notation for accessing items in an array/collection of objects contained within the object. For e.g. Item is the default property of an ArrayList (for that matter, IList.Item) which gets the object stored in the specified index. For eg :
Dim arrItems As New ArrayList
Console.WriteLine(CType(arrItems(0), String))
'Equivalent to this
'Console.WriteLine(CType(arrItems.Item(0), String))
In C#, default properties are called Indexers. There is a subtle difference in the way indexers are declared in VB.NET and C#. Here's an example (MSDN):
' Visual Basic
' A class that contains many Widgets
Public Class Widgets
'Default property implementation
Default Public Property Widget(ByVal I As Integer) As Widget
Get
' Implementation code to return a widget goes here.
End Get
Set(ByVal Value As Widget)
' Implementation code to set a widget goes here.
End Set
End Property
End Class
// C#
// Class that contains many Widgets.
public class Widgets
{
// Indexer implementation.
public Widget this[int index]
{
get
{
// Insert code to return a Widget.
}
set
{
// Insert code to set a Widget.
}
}
}
If you notice, there is no provision to specify the name of the Indexer in C#, as present in VB.NET. In C#, the name defaults to "Item". However, you can specify a name by means of an attribute as shown below:
[System.Runtime.CompilerServices.CSharp.IndexerName("Widget")]
public int this [int index] { }
Here are some other aspects of an Indexer we need to know:
1. You can have only one Default property/Indexer per class. The Indexer, however, can be overloaded.
2. Default properties should accept parameters. We cannot have VB6 like (parameterless) properties. Refer to this link
for Property changes in VB.NET as compared to VB.
Finally, a tip to end this note on indexers; a frequently asked question in the newsgroups. If we need to find out programmatically, if a class has an indexer, we can query a custom attribute called DefaultMemberAttribute attribute using Reflection as shown below:
static bool CheckIfIndexerPresent(Object obj)
{
object[] oAttributes = obj.GetType().GetCustomAttributes(true);
for(short j = 0; j < oAttributes.Length; j++)
{
if (oAttributes[j] is DefaultMemberAttribute)
{
return true;
}
}
return false;
}