Introduction

This post was inspired by this post by Damian Guard “8 things you probably didn’t know about C#”

The first point is that indexers can take params as a parameter so you can then give a list of items to get another list of items using the indexer.

Default properties and indexers

Lets take this collection as an example of how an indexer works.

Dim _list = New List(of String) From {"test1", "test2"}```
An indexer let’s you do this.

```vbnet
_list(0)```
This is exactly the same thing as 

```vbnet
_list.Item(0)```
When we look at the collection and the item property this would look something like this.

Default Public Property Item(index As Integer) As String Get ‘ Code here End Get Set(value As String) ‘ Code here End Set End Property``` The Default keyword is the key here. It determines which property is the indexer and which you can use without specifying it’s name.

But you can use this in your normal classes to.

Just look at this example.

Imports System.Reflection

Module Module1

    Sub Main()
        Dim s As New SomeCollection
        Console.WriteLine(s(0))
        For Each s1 In s({0, 1, 2})
            Console.WriteLine(s1)
        Next
        Console.ReadLine()
    End Sub

    Public Class SomeCollection

        Private _list As IList(Of String)

        Public Sub New()
            _list = New List(Of String) From {"test1", "test2", "test3", "test4"}
        End Sub

        Default Public ReadOnly Property Item(index As Integer) As String
            Get
                Return _list(index)
            End Get
        End Property

        Default Public ReadOnly Iterator Property Item(index() As Integer) As IEnumerable(Of String)
            Get
                For Each i In index
                    Yield _list(i)
                Next
            End Get
        End Property

    End Class

End Module

So I can use instance(0) to get one element or use instance({0,2}) to get a list of elements.

But I can also add more possibilities.

Imports System.Reflection

Module Module1

    Sub Main()
        Dim s As New SomeCollection
        For Each s1 In s({"test1", "test3"})
            Console.WriteLine(s1)
        Next
        Console.WriteLine(s("test1"))
        Console.ReadLine()
    End Sub

    Public Class SomeCollection

        Private _list As IList(Of String)

        Public Sub New()
            _list = New List(Of String) From {"test1", "test2", "test3", "test4"}
        End Sub

        Default Public ReadOnly Property Item(index As Integer) As String
            Get
                Return _list(index)
            End Get
        End Property

        Default Public ReadOnly Property Item(index As String) As Integer
            Get
                Return _list.IndexOf(index)
            End Get
        End Property

        Default Public ReadOnly Iterator Property Item(index() As String) As IEnumerable(Of Integer)
            Get
                For Each i In index
                    Yield _list.IndexOf(i)
                Next
            End Get
        End Property

    End Class

End Module

I now use a string as the indexer. I could even combine the integer and the string one in one class. And so much more.

This is the whole thing combined and in C#.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var s = new SomeCollection();
            Console.WriteLine(s[0]);
            foreach(var s1 in s[0,1,2])
            {
                Console.WriteLine(s1);
            }
            Console.WriteLine(s["test1"]);
            foreach (var s1 in s["test1", "test3"])
            {
                Console.WriteLine(s1);
            }
            Console.ReadLine();
        }
    }

    public class SomeCollection
    {

        private IList<String> _list;

        public SomeCollection()
        {
            _list = new List<String> {"test1", "test2", "test3", "test4"};
        }

        public String this[int index]
        {
            get { return _list[index]; }
        }

        public int this[String index]
        {
            get { return _list.IndexOf(index); }
        }

        public IEnumerable<String> this[params int[] index]
        {
            get { return index.Select(i => _list[i]); }
        }

        public IEnumerable<int> this[params String[] index]
        {
            get { return index.Select(i => _list.IndexOf(i)); }
        }
    }
}

And we see that in C# they use params. in VB.Net this is however not an option.

If you try this.

vbnet Default Public ReadOnly Iterator Property Item(ParamArray index() As String) As IEnumerable(Of Integer) Get For Each i In index Yield _list.IndexOf(i) Next End Get End Property Then you will get an error stating.

Properties with no required parameters cannot be declared ‘Default’.

Conclusion

The default property looks very different in VB.Net then it is in C# but it is there. And I’m sure not to many of used it in the last year.