Defining Default Indexers in Visual Basic
The approach for indexing collections differs between VB6 and Visual Basic .NET. In Visual Basic .NET you can define a property that permits you to treat an instance of a class as if it were itself an array. This property can be the default property, and only indexed properties can be default properties. This is a powerful capability in that it supports defining typed collections with flexible growth unavailable in an array and type-safety awareness in a generic collection. While you are not obliged to use indexers for just typed collections, this represents the best practical use for them.
In this article I will describe the refined behavior of the Default modifier and how you can define indexers for your custom, typed collections. These default indexers will allow you to index elements of an object using the customary integer as well as a string key value.
Expressing Default Properties
Every language has a grammar and rules that make up the grammar. Visual Basic 6 supported the Set keyword. When you defined a default property Visual Basic 6 could tell the difference between object assignment and default properties because you had to use Set when you were assigning objects; without Set VB6 could assume it had to look for a default property.
Visual Basic. NET does not use the Set keyword for object assignment, but like Visual Basic 6, .NET needs a code cue to indicate to the compiler when it should look for a default property. This code cue is the array operator pair (). For example, if you write object() then Visual Basic .NET assumes it is looking at an array or a default indexer property. If object is System.Array then it is the indexer operator and if object is some other type then the compiler looks for a default property. Thus, the presence of () becomes the replacement cue for Set in Visual Basic .NET.
Unlike VB6 though, only properties that have required parameters can be default properties. Listing 1 demonstrates a property without a parameter and Listing 2 shows a property with a parameter. Only the property in Listing 2 can be designated as a default property.
Listing 1: A property without a required argument.
Public Property UnitPrice() As Decimal Get Return FUnitPrice End Get Set(ByVal Value As Decimal) FUnitPrice = Value End Set End Property
Listing 2: A property with a required argument, or an indexed property.
Default Public Property Item(ByVal Index As Integer) As InventoryItem Get Return CType(List(Index), InventoryItem) End Get Set(ByVal Value As InventoryItem) List(Index) = InventoryItem End Set End Property
The argument Index is required. (That is, it is present and it doesn't use the Optional modifier.) Hence, Item can be expressed as a default property. This means that instances of classes containing Item could be written with or without the express use of the property named Item, as in the following:
Object.Item(5) = New InventoryItem()
is equivalent to
Object(5) = New InventoryItem()
To summarize, there are a couple of differences between properties that can be default and those that can not. Default properties use the Default modifier (see listing 2). Default properties must have a required argument. Objects containing default properties can use the long or short version of the property access.