Home

Introduction to Indexed Properties

 

A Property Can Be Indexed

 

Introduction

We learned how to create an array, how to assign values to its elements, and how to get the value of each element. Here is an example:

using namespace System;

int main()
{
    array<double> ^ Numbers = gcnew array<double>(5);

    Numbers[0] = 927.93;
    Numbers[1] = 45.155;
    Numbers[2] = 2.37094;
    Numbers[3] = 73475.25;
    Numbers[4] = 186.72;

    for(int i = 0; i < Numbers->Length; i++)
        Console::WriteLine(L"Number {0}: {1}", i+1, Numbers[i]);

    Console::WriteLine();
    return 0;
}

This would produce:

Number 1: 927,93
Number 2: 45,155
Number 3: 2,37094
Number 4: 73475,25
Number 5: 186,72

Press any key to continue . . .

In the same way, if we declared an array as a member variable of a class, to access the elements of that member, we had to use an instance of the class, followed by the period operator, followed by the member variable applied with the square brackets. Instead of accessing each element through its member variable, you can create a type of property referred to as an indexer.

Practical Learning: Introducing Indexed Properties

  1. Start Microsoft Visual C++ 2005
  2. To start a new, on the main menu, click File -> New -> Project...
  3. In the Project Types, make sure Visual C++ is selected.
    In the Templates list, click CLR Empty Project
  4. Set the Name to PropertyRental1
  5. To create a new class, on the main menu, click Project -> Add Class...
  6. In the Categories, select C++.
    In the Templates list, click C++ Class and click Add
  7. Set the Name to CRentalProperty and click Finish Enter
  8. Change the file as follows:
     
    #pragma once
    
    using namespace System;
    
    public ref class CRentalProperty
    {
    public:
        long propCode;
        String ^ cond;
        short beds;
        double baths;
        double val;
    
    public:
        property long PropertyCode
        {
            long get() { return propCode; }
            void set(long value) { propCode = value; }
        }
    
        property String ^ PropertyCondition
        {
            String ^ get() { return cond; }
            void set(String ^ value) { cond = value; }
        }
    
        property short Bedrooms
        {
            short get() { return beds; }
            void set(short value) { beds = value; }
        }
    
        property double Bathrooms
        {
            double get() { return (baths <= 0) ? 0.00 : baths; }
            void set(double value) { baths = value; }
        }
    
        property double MonthlyRent
        {
            double get() { return (val <= 0) ? 0.00 : val; }
            void set(double value) { val = value; }
        }
    
    	CRentalProperty(void);
    };
  9. Access the RentalProperty.cpp file and change the constructor as follows:
     
    #include "RentalProperty.h"
    
    CRentalProperty::CRentalProperty(void)
    {
        Random ^ rnd = gcnew Random;
        propCode = rnd->Next(100000, 999999);
        cond = L"Unknown";
        beds = 0;
        baths = 0.0;
        val = 0.00;
    }
  10. To create a new class, on the main menu, click Project -> Add Class...
  11. In the Categories, make sure C++ is selected.
    In the Templates list, click C++ Class and click Finish
  12. Set the Name to CPropertyListing and click Finish
  13. Change the file as follows:
     
    #pragma once
    
    #include "RentalProperty.h"
    
    public ref class CPropertyListing
    {
    public:
        array<CRentalProperty ^> ^ props;
    
    public:
    	CPropertyListing(void);
    };
  14. Access the PropertyListing.cpp file and change the constructor as follows:
     
    #include "PropertyListing.h"
    
    CPropertyListing::CPropertyListing(void)
    {
        Random ^ rnd = gcnew Random;
        props = gcnew array<CRentalProperty ^>(40);
    
        // Create a few properties ready to be rented
        props[0] = gcnew CRentalProperty;
        props[0]->PropertyCode = rnd->Next(100000, 999999);
        props[0]->PropertyCondition = L"Excellent";
        props[0]->Bedrooms = 5;
        props[0]->Bathrooms = 3.5;
        props[0]->MonthlyRent = 2650;
    
        props[1] = gcnew CRentalProperty;
    	props[1]->PropertyCode = rnd->Next(100000, 999999);
    	props[1]->PropertyCondition = L"Excellent";
    	props[1]->Bedrooms = 3;
    	props[1]->Bathrooms = 2.5;
    	props[1]->MonthlyRent = 1750;
    
    	props[2] = gcnew CRentalProperty;
    	props[2]->PropertyCode = rnd->Next(100000, 999999);
    	props[2]->PropertyCondition = L"Good";
    	props[2]->Bedrooms = 4;
    	props[2]->Bathrooms = 2.5;
    	props[2]->MonthlyRent = 2450;
    
    	props[3] = gcnew CRentalProperty;
            props[3]->PropertyCode = rnd->Next(100000, 999999);
            props[3]->PropertyCondition = L"Excellent";
    	props[3]->Bedrooms = 1;
    	props[3]->Bathrooms = 1.0;
    	props[3]->MonthlyRent = 880;
    
    	props[4] = gcnew CRentalProperty;
    	props[4]->PropertyCode = rnd->Next(100000, 999999);
    	props[4]->PropertyCondition = L"Excellent";
    	props[4]->Bedrooms = 3;
    	props[4]->Bathrooms = 2.5;
    	props[4]->MonthlyRent = 1880;
    
    	props[5] = gcnew CRentalProperty;
    	props[5]->PropertyCode = rnd->Next(100000, 999999);
    	props[5]->PropertyCondition = L"Good";
    	props[5]->Bedrooms = 2;
    	props[5]->Bathrooms = 1.0;
    	props[5]->MonthlyRent = 1050;
    
        // Since we don't yet have a complete list of properties
        // Create some empty ones
        for (int i = 6; i < 40; i++)
        {
            props[i] = gcnew CRentalProperty;
        }
    }
  15. To create a new file, on the main menu, click Project -> Add New Item...
  16. In the Categories, click Code
  17. In the Templates list, click C++ File (.cpp)
  18. Set the Name to Exercise and click Add
  19. Access the Program.cs file and change it as follows:
     
    using namespace System;
    
    #include "PropertyListing.h"
    
    int main()
    {
        CPropertyListing ^ properties = gcnew CPropertyListing;
        CRentalProperty ^ prop = gcnew CRentalProperty;
    
        for(int i = 0; i < 6; i++)
        {
            Console::WriteLine(L"{0}.----------------------------------",
    			i + 1);
            Console::WriteLine(L"Property #:   {0}",
    			  properties->props[i]->PropertyCode);
            Console::WriteLine(L"Condition:    {0}",
    			  properties->props[i]->PropertyCondition);
            Console::WriteLine(L"Bedrooms:     {0}",
    			  properties->props[i]->Bedrooms);
            Console::WriteLine(L"Bathrooms:    {0}",
    			  properties->props[i]->Bathrooms);
            Console::WriteLine(L"Market Value: {0}\n",
    		properties->props[i]->MonthlyRent.ToString("C"));
        }
        Console::WriteLine(L"======================================");
    
        return 0; 
    }
  20. Press Ctrl + F5 to execute the application. This would produce:
     
    1.----------------------------------
    Property #:   920119
    Condition:    Excellent
    Bedrooms:     5
    Bathrooms:    3.5
    Market Value: $2,650.00
    
    2.----------------------------------
    Property #:   587917
    Condition:    Excellent
    Bedrooms:     3
    Bathrooms:    2.5
    Market Value: $1,750.00
    
    3.----------------------------------
    Property #:   904376
    Condition:    Good
    Bedrooms:     4
    Bathrooms:    2.5
    Market Value: $2,450.00
    
    4.----------------------------------
    Property #:   421662
    Condition:    Excellent
    Bedrooms:     1
    Bathrooms:    1
    Market Value: $880.00
    
    5.----------------------------------
    Property #:   305196
    Condition:    Excellent
    Bedrooms:     3
    Bathrooms:    2.5
    Market Value: $1,880.00
    
    6.----------------------------------
    Property #:   503836
    Condition:    Good
    Bedrooms:     2
    Bathrooms:    1
    Market Value: $1,050.00
    
    ======================================
    Press any key to continue . . .
  21. Close the DOS window

An Indexed Property

An indexer, also called an indexed property, is a class's property that allows you to access a member variable of a class using the features of an array. To create an indexed property, start the class like any other. In the body of the class, create a member variable that is an array and initialize it appropriately. Here is an example:

public ref class CNumber
{
    array<double> ^ Numbers;

public:
    CNumber()
    {
	Numbers = gcnew array<double>(5);
    }
};

Then, in the body of the class, create a property named default with its accessor(s). The default property must be the same type as the member variable it will refer to. The property must take a parameter as an array. This means that it must have square brackets. Inside of the brackets, include the parameter type you will use as index to access the members of the array.

Traditionally, and as we have seen so far, you usually access the members of an array using an integer-based index. Therefore, you can use an int type as the index of the array but the index' parameter must not have a name. This would be done as follows:

public ref class CNumber
{
    array<double> ^ Numbers = gcnew double[5];

public:
    property double default[int]
    {
    }
}

If you want the property to be read-only, include only a get accessor.

When creating the get accessor, you must pass a parameter to it. The parameter must be the same type you passed to the default property, except that, as mentioned above, the parameter passed to default must not have a name but the parameter passed to get must have a name. When implementing the get accessor, it must return an element of the array member variable the property refers to, using the parameter passed to get. This would be done as follows:

public ref class CNumber
{
    array<double> ^ Numbers;

public:
    CNumber()
    {
	Numbers = gcnew array<double>(5);
    }

    property double default[int]
    {
	double get(int i) { return Numbers[i]; }
    }
};

Once you have created the indexed property, the class can be used. To start, you can declare a handle of the class. To access its arrayed member variable, you can apply the square brackets directly to it. Here is an example:

using namespace System;

public ref class CNumber
{
    array<double> ^ Numbers;

public:
    CNumber()
    {
	Numbers = gcnew array<double>(5);
        Numbers[0] = 927.93;
        Numbers[1] = 45.155;
        Numbers[2] = 2.37094;
        Numbers[3] = 73475.25;
        Numbers[4] = 186.72;
    }

    property double default[int]
    {
	double get(int i) { return Numbers[i]; }
    }
};

int main()
{
    CNumber ^ nbr = gcnew CNumber;

    for(int i = 0; i < 5; i++)
        Console::WriteLine(L"Number {0}: {1}", i + 1, nbr[i]);

    Console::WriteLine();
    return 0;
}

Indexed Properties of Other Primitive Types

In the above example, we created a property that produced double-precision values. When creating an indexed property, you will decide what type of value the property must produce or the type it can have. As opposed to an int or a double, you can also create a property that takes or produces a string. Here is an example of a string-based indexed property:

using namespace System;

public ref class CPhilosopher
{
    array<String ^> ^ phil;

public:
    property String ^ default[int]
    {
        String ^ get(int i) { return phil[i]; }
    }

    CPhilosopher()
    {
	phil = gcnew array<String ^>(8);

        phil[0] = L"Aristotle";
        phil[1] = L"Emmanuel Kant";
        phil[2] = L"Tom Huffman";
        phil[3] = L"Judith Jarvis Thompson";
        phil[4] = L"Thomas Hobbes";
        phil[5] = L"Cornell West";
        phil[6] = L"Jane English";
        phil[7] = L"James Rachels";
    }
};

int main()
{
    CPhilosopher ^ thinker = gcnew CPhilosopher;

    for(int i = 0; i < 8; i++)
        Console::WriteLine(L"Philosopher: {0}", thinker[i]);

    Console::WriteLine();
    return 0;
}

This would produce:

Philosopher: Aristotle
Philosopher: Emmanuel Kant
Philosopher: Tom Huffman
Philosopher: Judith Jarvis Thompson
Philosopher: Thomas Hobbes
Philosopher: Cornell West
Philosopher: Jane English
Philosopher: James Rachels

Press any key to continue . . .

In the same way, you can created a Boolean-based indexed property by simply making it return a bool type. Here is an example:

using namespace System;

public ref class CDrivingWhileIntoxicated
{
    array<bool>^ dwi;

public:
    property bool default[int]
    {
        bool get(int i) { return dwi[i]; }
    }

    CDrivingWhileIntoxicated()
    {
	dwi = gcnew array<bool>(7);

        dwi[0] = false;
        dwi[1] = true;
        dwi[2] = true;
        dwi[3] = false;
        dwi[5] = false;
        dwi[6] = false;
    }
};

int main()
{
    CDrivingWhileIntoxicated ^ driving = gcnew CDrivingWhileIntoxicated;

    Console::WriteLine(L"Police Report");
    Console::WriteLine(L"-------------------------------");
    for(int i = 0; i < 7; i++)
            Console::WriteLine(L"Driver Was Intoxicated: {0}", driving[i]);

    Console::WriteLine();
    return 0;
}

This would produce:

Police Report
-------------------------------
Driver Was Intoxicated: False
Driver Was Intoxicated: True
Driver Was Intoxicated: True
Driver Was Intoxicated: False
Driver Was Intoxicated: False
Driver Was Intoxicated: False
Driver Was Intoxicated: False

Press any key to continue . . .

Using a Non-Integer-Based Index

In Lesson 25, we saw how to create different arrays that are numeric or string based. Here is an example of a float array:

using namespace System;

int main()
{
    array<float>^  ages = gcnew array<float>(5);

    ages[0] = 14.50f;
    ages[1] = 12.00f;
    ages[2] = 16.50f;
    ages[3] = 14.00f;
    ages[4] = 15.50f;

    Console::WriteLine(L"Student Age: {0}", ages[2]);
    Console::WriteLine();
    return 0;
}

When we think of arrays, we usually consider passing an integer-based parameter to the square brackets of the variable, as done for the above ages array:

array<float>^  ages = gcnew array<float>(5);

When using an indexed property, you can use almost any type of index, such as a real value or a string. To do this, in the square brackets of the default property, pass the desired type as the index. Here is an example:

public ref class CStudentAge
{
    property float default[string]
    {
    }
};

When defining the indexed property, there are two rules you must follow and you are aware of them already because an indexed property is like a method that takes a parameter and doesn't return void. Therefore, when implementing an indexed property, make sure you return the right type of value in the get accessor and make sure you pass the appropriate index to the return value of the default property. Here is an example:

public ref class CStudentAge
{
public:
    property float default[String ^]
    {
        float get(String ^ name)
        {
            if(  name == L"Ernestine Jonas" )
                return 14.50f;
            else if( name == L"Paul Bertrand Yamaguchi" )
                return 12.50f;
            else if( name == L"Helene Jonas" )
                return 16.00f;
            else if( name == L"Chrissie Hanson" )
                return 14.00f;
            else if( name == L"Bernard Hallo" )
                return 15.50f;
            else
                return 12.00f;
        }
    }
};

Once you have defined the property, you can use it. To access any of its elements, you must pass the appropriate type of index. In this case, the index must be passed as a string and not an integer. You can then do whatever you want with the value produced by the property. For example, you can display it to the user. Here is an example:

using namespace System;

public ref class CStudentAge
{
public:
    property float default[String ^]
    {
        float get(String ^ name)
        {
            if(  name == L"Ernestine Jonas" )
                return 14.50f;
            else if( name == L"Paul Bertrand Yamaguchi" )
                return 12.50f;
            else if( name == L"Helene Jonas" )
                return 16.00f;
            else if( name == L"Chrissie Hanson" )
                return 14.00f;
            else if( name == L"Bernard Hallo" )
                return 15.50f;
            else
                return 12.00f;
        }
    }
};

int main()
{
    CStudentAge ^ sa = gcnew CStudentAge;
    float age = sa[L"Paul Bertrand Yamaguchi"];

    Console::WriteLine(L"Student Age: {0}", age);
    Console::WriteLine();
    return 0;
}

This would produce:

Student Age: 12.5

Press any key to continue . . .

You can also pass an enumeration as an index. To do this, after defining the enumerator, type its name in the square brackets of the default member, then define the property as you see fit. To access the property outside, apply an enumeration member to the square brackets on an instance of the class. Here is an example:

using namespace System;

public enum CategoryFee
{
    Children,
    Adult,
    Senior,
    Unknown
};

public ref class CGolfClubMembership
{
    array<double> ^ fee;

public:
	CGolfClubMembership()
    {
		fee = gcnew array<double>(4);
        fee[0] = 150.95;
        fee[1] = 250.75;
        fee[2] = 85.65;
        fee[3] = 350.00;
    }

    property double default[CategoryFee]
    {
        double get(CategoryFee cat)
        {
            if (cat == CategoryFee::Children)
                return fee[0];
            else if (cat == CategoryFee::Adult)
                return fee[1];
            else if (cat == CategoryFee::Senior)
                return fee[2];
            else
                return fee[3];
        }
    }
};

int main()
{
    CGolfClubMembership ^ mbr = gcnew CGolfClubMembership;

    Console::WriteLine(L"Membership Fee: {0}",
		mbr[CategoryFee::Senior]);

    Console::WriteLine();
    return 0;
}

This would produce:

Membership Fee: 85.65

Press any key to continue . . .

Practical Learning: Creating an Indexer

  1. To create an indexed propertyr, access the PropertyListing.h header file and change it as follows:
     
    #pragma once
    
    #include "RentalProperty.h"
    
    public ref class CPropertyListing
    {
    public:
        array<CRentalProperty ^> ^ props;
    
        property String ^ default[long]
        {
            String ^ get(long code)
    	{
                for(int i = 0; i < props.Length; i++)
                    if( code == props[i]->PropertyCode )
                        return L"Property #:   " + props[i]->PropertyCode + 
                                   L"\nCondition:    " + 
    				    props[i]->PropertyCondition +
                                   L"\nBedrooms:     " + props[i]->Bedrooms + 
                                   L"\nBathrooms:    " + props[i]->Bathrooms +
                                   L"\nMonthly Rent: " + 
    				    props[i]->MonthlyRent.ToString("C");
                return L"Unidentifiable Property";
    	}
        }
    
    public:
    	CPropertyListing(void);
    };
  2. Access the Exercise.cpp file and change it as follows:
     
    using namespace System;
    
    #include "PropertyListing.h"
    
    int main()
    {
        CPropertyListing ^ properties = gcnew CPropertyListing;
        long lngCode;
    
        Console::WriteLine(L"Here is a list of our properties by code");
        for (int i = 0; i < 6; i++)
            Console::WriteLine(L"Property Code: {0}",
    			properties->props[i]->PropertyCode);
    
        try
        {
    	Console::Write(L"Enter Property Code: ");
    	lngCode = long::Parse(Console::ReadLine());
    
            Console::WriteLine(L"======================================");
            Console::WriteLine(L"Property Information");
            Console::WriteLine(L"--------------------------------------");
            Console::WriteLine(properties[lngCode]);
            Console::WriteLine(L"======================================");
        }
        catch(FormatException ^)
        {
            Console::WriteLine(L"=- Invalid Property Code -=");
        }
    
        return 0; 
    }
  3. Press Ctrl + F5 to execute the application. Here is an example:
     
    Here is a list of our properties by code
    Property Code: 355443
    Property Code: 653004
    Property Code: 800118
    Property Code: 839375
    Property Code: 148561
    Property Code: 697001
    Enter Property Code: 697001
    ======================================
    Property Information
    --------------------------------------
    Property #:   697001
    Condition:    Good
    Bedrooms:     2
    Bathrooms:    1
    Monthly Rent: $1,050.00
    ======================================
    Press any key to continue . . .
  4. Close the DOS window
 

Home Copyright © 2007-2012 FunctionX Next