#592 – Optional Parameters in Indexers

In addition to defining optional parameters within methods, you can also include an optional parameter in an indexer.

For example, assume that we have a Dog class that keeps track of the sounds that a dog makes when he barks and that we’ve defined an indexer for the class that retrieves a “bark sound” from that list.

        public string this[int i]
        {
            get
            {
                return BarkRecord[i];
            }
        }

Using the indexer:

            kirby.Bark("Woof");
            kirby.Bark("Bow-wow");
            kirby.Bark("Urgh");

            Console.WriteLine(kirby[2]);


We can now add an optional parameter to the indexer, to indicate that we’d like the date/time of the bark returned as well.

        public string this[int i, bool includeTime = false]
        {
            get
            {
                string barkInfo = BarkRecord[i];

                if (includeTime)
                    barkInfo = barkInfo + string.Format(" at {0}", BarkTime[i]);

                return barkInfo;
            }
        }

Using the indexer:

            Console.WriteLine("Bark at [2]={0}", kirby[2]);
            Console.WriteLine("Bark at [1]={0}", kirby[1, true]);

Advertisements

#366 – Defining an Indexer with More than One Parameter

An indexer will typically have a single parameter, often based on an integer type.

        public LogMessage this[int i]
        {
            get { return messages[i]; }
            set { messages[i] = value; }
        }

You can also define an indexer that takes more than one parameter.  In the example below, we have an internal data structure that stores a list of messages for each day of the week.  We can retrieve a specific message by passing in a parameter representing the day, as well as a 0-based index into the list of messages for that day.

            // Get 1st Saturday message
            LogMessage msg = log[Days.Sat, 0];

Here’s what the definition of the indexer looks like.

        private Dictionary<Days, List<LogMessage>> dailyMessages = new Dictionary<Days, List<LogMessage>>();

        public LogMessage this[Days day, int i]
        {
            get { return dailyMessages[day][i]; }
        }

#365 – Overloading an Indexer

You can define several versions of an indexer in a class, each indexed using a different type, overloading the indexer.

In the example below, we can index using the Days enumerated type or a 0-based integer representing the day.

    public class Logger
    {
        private Dictionary<Days, LogMessage> dailyMessages = new Dictionary<Days, LogMessage>();

        public LogMessage this[Days day]
        {
            get { return dailyMessages[day]; }
            set { dailyMessages[day] = value; }
        }

        public LogMessage this[int i]
        {
            get { return dailyMessages[(Days)i]; }
            set { dailyMessages[(Days)i] = value; }
        }
    }

Using this class, we could then index using either the Days or the integer type.

            Logger log = new Logger();

            log[Days.Mon] = new LogMessage("Monday was a good day");
            log[2] = new LogMessage("Tuesday not bad either");

In this example, we indexed into the same internal data object.  But we could have also indexed into different objects, depending on the indexer’s type.

#362 – Defining an Indexer

An indexer is a class member that allows client code to index into an instance of class using an integer-based (0..n-1) index.  The indexer allows an instance of a class to behave like an array.

Assume that we define a Logger class that stores a series of log messages in an internal collection:

    public class Logger
    {
        private List<LogMessage> messages = new List<LogMessage>();

        public void LogAMessage(LogMessage msg)
        {
            messages.Add(msg);
        }

    }

We define an indexer by defining a member that looks like a property, but uses the this keyword.

        public LogMessage this[int i]
        {
            get
            {
                return messages[i];
            }
        }

The indexer allows us to write code that indexes into an instance of the class:

            Logger log = new Logger();

            log.LogAMessage(new LogMessage("This happened", 5));
            log.LogAMessage(new LogMessage("Something else happened", -1));

            LogMessage lm = log[1];   // returns 2nd element