Learning C# and OOP, Indexers, Part 2

Baldwin applies indexers to the simple Radio program discussed in an earlier lesson.

Published:  November 3, 2002
By Richard G. Baldwin

C# Programming Notes # 108b


Preface

This lesson is part of a miniseries designed to teach you how to write object-oriented programs using C#.  The first lesson in the miniseries was entitled Learning C# and OOP: Getting Started, Objects and Encapsulation.  The previous lesson was entitled Learning C# and OOP, Indexers, Part 1.

No prerequisite C# or OOP knowledge required

The miniseries assumes no prerequisite knowledge of C# syntax or OOP concepts.  If you have a general understanding of computer programming, you should be able to read and understand the lessons in this miniseries.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

Properties

In previous lessons, you learned about the use of simple properties and indexed properties in both C# and Java.  You learned that the most important aspect of properties in both programming environments is their use in reflection in C# and introspection in Java.  I showed you an example of those processes in both languages.

Indexed properties

An indexed property is a property that is capable of storing more than one value based on an index, and is capable of returning any of the values associated with a specific index.

(Properties of this type are most commonly referred to as indexed properties in Java, while they are more commonly referred to simply as indexers in C#.

Indexers and classes

A previous lesson entitled Learning C# and OOP, Classes, developed a simple C# program, which simulated the manufacture and use of the car radio.  This lesson will revise the program from that previous lesson to incorporate the use of the C# indexers.

Manufacture and use of a car radio

As before, a simple C# program will be discussed to illustrate the definition and use of two different classes.  Taken in combination, these two classes simulate the manufacture and use of a car radio.

Create a new Radio object

You will see how to write code to create a new Radio object by applying the new operator to the class named Radio.  You will also see how to save that object's reference in a reference variable of type Radio.

Program the car radio using an indexer

You will see how to write code that is used to simulate the association of a radio button with a particular radio station.  The code used to accomplish this makes use of a C# indexer.

The plans for a car radio

You will see the definition of a class named Radio.  This class includes an instance variable that refers to an array object.  The array object is combined with some additional rather cryptic code to form an indexer.

The driver

You will see the definition of a class named Radio01a.  This class consists solely of the Main method.  The Main method of a C# program is executed by the C# Common Language Runtime (CLR) when the program is run.  Thus, it is the driver for the entire program.

Discussion and Sample Code

What is a class?

A class is a plan from which many objects can be created.  I previously likened the class definition to the plans from which millions of nearly identical car radios can be produced.

The car radio example

Listing 6, near the end of the lesson shows the code for a simple C# program named Radio01a
This program simulates the manufacture and use of a car radio.  This program is very similar to the program named Radio01 in the earlier lesson, which did not use indexers.

Explain in fragments

In order to help you to focus specifically on important sections of code, I will explain the behavior of this program in fragments.

This program contains two top-level class definitions, Radio and Radio01a.

The Radio class

Listing 1 shows the entire class definition for the Radio class with the material that is new to this lesson highlighted in boldface.
 
class Radio{
  protected double[] stationNumber = 
                         new double[5];

  //Define an indexer
  public double this[int i]{
    set{//Define the set block
      //validation code as needed
      stationNumber[i] = value;
    }//end set

    get{//Define the get block
      //validation code as needed
      return stationNumber[i];
    }//end get
  }//end this indexer

  //...Code deleted for brevity
  
}//end class Radio

Listing 1

Setting a radio frequency

The code in the set block of Listing 1 is used to simulate the association of a particular button with a particular radio station by the user.

Two incoming parameters

The code in the set block in Listing 1 receives two incoming parameters (although they don't appear in the form of normal method parameters):

  1. An integer that corresponds to a button number (button numbers are assumed to begin with 0 and extend through 4 in order to match array indices)
  2. A frequency value to be associated with the indicated button.

Save the frequency value

The code in the set block stores the frequency value in an element of the array object referred to by stationNumber.  The element number is specified by the value of the index shown in square brackets in the assignment statement.

Very cryptic setter and getter constructs

As you can see, and as was explained in the previous lesson on indexers, this approach to setting and getting properties involves some very cryptic code, which is peculiar to C#.

As you will see later, it appears to the user that setter and getter methods are not being invoked when property values are being set and retrieved.  However, as you can see from Listing 1, there is code inside the set and get blocks that is being invoked.

Validation code can be used if needed

This makes it possible for the programmer of the Radio class to insert validation code inside the set and get blocks shown in Listing 1, if needed.

For example, if I had intended for this to be a robust program, I probably would have put code in the set and get blocks to confirm that the incoming index was within the bounds of the array referred to by the reference variable named stationNumber

I might also have inserted code in the set block to confirm that the incoming frequency value is a valid frequency value (for example, a valid frequency value cannot be negative).

The remaining code

The remaining code in the Radio class is the same as was discussed in the program named Radio01 in a previous lesson.  Therefore, I won't discuss it further in this lesson.

The class named Radio01a

The class named Radio01a is shown in its entirety in Listing 2.  An object of this class simulates the manufacturer and the user of the radio object.
 
public class Radio01a{
  public static void Main(){
    //This is the manufacturer of the
    // radio
    Radio myRadio = new Radio();
    
    //This is the user of the radio
    //Invoke an indexer set block
    myRadio[3] = 93.5;
    //Invoke an indexer get block
    int i = 3;
    System.Console.WriteLine("Button "
              + i + " frequency is " +
                myRadio[3] + " Mhz");
    //Now perform an operation
    myRadio.playStation(3);
  }//end Main
}//end class Radio01a

Listing 2

Concentrate on code that is different

Most of the code in Listing 2 is identical to that discussed in a previous lesson for the program named Radio01.  Therefore, I will concentrate on those aspects of this program that are different from the previous program.  In particular, I will emphasize the use of the indexer to store the radio station frequencies in this program.

The class named Radio01a consists solely of the Main method.  The Main method of a C# program is executed by the C# CLR when the program is run.  Thus, it is the driver for the entire application.

The driver class

An object instantiated from the code in Listing 2 simulates the manufacturer of the radio and the use of the radio by the end user.

Without getting into a lot of detail regarding C# syntax, I will further subdivide and discuss this code in the following fragments.

Constructing a Radio object

As discussed in a previous lesson, the code in Listing 3 applies the new operator to the constructor for the Radio class, causing a new object to be created according to the plans specified in the class named Radio.
 
     Radio myRadio = new Radio();

Listing 3

Saving a reference to the Radio object

Also as discussed in a previous lesson, the code in Listing 3 declares a reference variable named myRadio, of type Radio, and stores the new object's reference in that variable.

Programming the radio buttons

The code in Listing 4 is new to this program.  This statement simulates the process of associating a particular radio station with a particular button on the front of the radio.

(Listing 4 also shows the corresponding code from the previous program to highlight the differences between the two approaches.)

   //myRadio.setStationNumber(3,93.5);
    myRadio[3] = 93.5;

Listing 4

Invoking a setter method

The statement from the previous program, (shown as a comment in Italics in Listing 4), associates a simulated frequency selector button with a simulated radio station.  This is accomplished by invoking the method named setStationNumber on the reference to the Radio object.

This is a common approach to storing data in the instance variables of an object in C++ and Java.  (It is also a design pattern for an indexed property in Java.)

Also works fine in C#

This approach also works just fine in C#, but the designers of C# came up with an alternative way to set property values in C#.

Something is happening behind the scenes

The non-Italic statement in Listing 4 shows the special syntax used to set the value of an indexer in C#. 

Looks like an assignment to an array object

As you can see, it appears to the user that this syntax doesn't entail the invocation of a setter method.  The statement appears simply to be the assignment of a double value to an array element at index 3.

The reference to the Radio object is being treated as though the object is an array object, even though it wasn't declared as such.

(As we saw earlier, this does entail the invocation of code in a set block, but it happens behind the scenes insofar as the user of the Radio object is concerned.  One effect is to give the user access to a non-public instance variable of the Radio class just as though it were public.)

Button 3 associated with frequency of 93.5

The code in Listing 4 causes radio button number 3 to be associated with the frequency 93.5 MHz.  (The value 93.5 is stored in the indexer element that represents button number 3.)

Illustrate the get side of the indexer

Just to illustrate the get side of the indexer, the code in Listing 5 gets and displays the frequency value stored in the indexer at index 3.  (This is somewhat analogous to the display on my car radio, but the analogy is very weak.)
 
    System.Console.WriteLine(
            "Button 3 frequency is " +
                 myRadio[3] + " Mhz");

Listing 5

The important part of the code in Listing 5 is highlighted in boldface. 

Appears to access an array element

Again, it appears that this code simply accesses an element in an array at index 3, and that the get operation doesn't entail the invocation of a getter method.  However, as we saw earlier, code in a get block is actually invoked behind the scenes.

The code in Listing 5 produces the following output on the screen.

Button 3 frequency is 93.5 Mhz

Remaining code

The remaining code in the Radio01a class is identical to the code that I discussed in the program named Radio01 in a previous lesson.  Therefore, I am going to skip the remaining code.

Summary

This lesson has concentrated primarily on a discussion of the C# class and a C# indexer.

A simple C# program was discussed to illustrate the definition and use of two different classes.  Taken in combination, these two classes simulate the manufacture and use of the car radio object discussed in an earlier lesson.

You saw how to write code to create a new Radio object by applying the new operator to the constructor for the class named Radio.  You also saw how to save that object's reference in a reference variable of type Radio.

You saw how to write code using an indexer to simulate the association of a radio button with a particular radio station.

You saw the definition of the class named Radio01a, which consists solely of the Main method.  The Main method of a C# program is executed by the C# Common Language Runtime (CLR) when the program is run.

You saw the definition of the class named Radio.   This class includes an instance variable that refers to an array object.  The array object is combined with some additional cryptic code to form an indexer.

Complete Program Listing

A complete listing of the program is shown in Listing 6.
 

/*File Radio01a.cs
Copyright 2002, R.G.Baldwin
Simulates manufacture and use of a 
car radio.

This program produces the following
output on the computer screen:
  
Button 3 frequency is 93.5 Mhz
Playing the station at 93.5 Mhz
**************************************/

public class Radio01a{
  //This class simulates the 
  // manufacturer and the human user
  public static void Main(){
    //This is the manufacturer of the
    // radio
    Radio myRadio = new Radio();
    
    //This is the user of the radio
    //Invoke an indexer set block
    myRadio[3] = 93.5;
    //Invoke an indexer get block
    System.Console.WriteLine(
           "Button 3 frequency is " +
                myRadio[3] + " Mhz");
    //Now perform an operation
    myRadio.playStation(3);
  }//end Main
}//end class Radio01a
  //---------------------------------//

class Radio{
  //This class simulates the plans from
  // which the radio object is created.
  protected double[] stationNumber = 
                         new double[5];

  //Define a property indexer
  public double this[int i]{
    //Define the set block of a 
    // property indexer
    set{  
      stationNumber[i] = value;
    }//end set
    
    //Define the get block of the 
    // property indexer to illustrate
    // the syntax.
    get{
      return stationNumber[i];
    }//end get
  }//end this indexer

  //Make this method virtual for
  // overriding in a subsequent lesson
  public virtual void playStation(
                            int index){
    System.Console.WriteLine(
            "Playing the station at " 
               + stationNumber[index]
               + " Mhz");
  }//end method playStation
  
}//end class Radio

Listing 6


Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

baldwin@DickBaldwin.com

-end-

 


© 1996, 1997, 1998, 1999, 2000, 2001, 2002 Richard G. Baldwin