Managed Extensions for C++ Specification
13.2 Indexed Properties

A property is indexed if its get and set methods fit the following description.

  • The get method has parameter tuple (T1, ..., TN), and has return type TR which can be any type.
  • The set method has parameter tuple (T1, ..., TN , TR) and void return type.

Given indexed property methods, a pseudo member array is injected with the following form (assuming property name F):

/*   TR   F[T1, ... ,TN ];   */   // compiler generated pseudo member
/*   TR   F[T1] ... [TN ];   */   // compiler generated pseudo member

A property provides array-like access to the pseudo member. However, because it is implemented using method calls, any parameter type can be used to index the pseudo member array.

Example

// __property2.cpp
// compile with: /clr
#using <mscorlib.dll>
using namespace System;

__gc class Employee {
public:
   Employee(String * s, int d) {
      _name = s;
      _dept = d;
   };

   __property String * get_name() { return _name; }

   __property int get_dept() { return _dept; }

private:
   String * _name;
   int _dept;
};

__gc class Manager {
public:
   __property Employee * get_Report(String * s) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> name != s)
         ;
      pEmp = pEmp -> next);
      if (pEmp)
         return pEmp -> emp;
      else
         return 0;
   }

   __property void set_Report(String* s, Employee* e) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> name != s)
         ;
      pEmp = pEmp -> next);
      if (!pEmp) {
         EmpList * emp1 = new EmpList; 
         emp1 -> emp = e; 
         emp1 -> next = Reports; 
         Reports = emp1;
      }
   }

private:
   __gc struct EmpList {
   Employee * emp;
   EmpList * next;
   };

   EmpList * pEmp;
   static EmpList * Reports = 0;
};

/* Employee* Report[ String* ]; */    // pseudo array member
int main() {
   Manager*  Ed = new Manager;
   Employee* Bob = new Employee(S"Bob Smith", 12);
   Employee* Gus = new Employee(S"Gus Jones", 18);

   // track Ed's reports
   Ed->Report[ Bob->name ] = Bob;   // indexed by String* type
   Ed->Report[ Gus->name ] = Gus;   // indexed by String* type
   Console::WriteLine(Ed->Report[ Bob->name ]->dept);
}

Output

12

The pseudo member array is indexed in a similar way to a C++ array.

Example

// __property3.cpp
// compile with: /clr
#using <mscorlib.dll>
using namespace System;

public __gc
class X {
public:
   __property int get_Prop(int i, int j) {
      return m_val - i - j;
   }
   __property void set_Prop(int i, int j, int value) {
      m_val = value + i + j;
   }
   int m_val;
};
int main() {
   X* x = new X;
   x->Prop[1][2] = 3;
   Console::WriteLine(x->Prop[1][2]);
}

Output

3

An indexed property can be overloaded like any normal member function.

Example

// __property4.cpp
// compile with: /clr
#using <mscorlib.dll>
using namespace System;

__gc class PhoneNumber {
public:
   PhoneNumber(int AreaCode, int ThreeDigits, int FourDigits) {
      _AreaCode = AreaCode; 
      _ThreeDigits = ThreeDigits; 
      _FourDigits = FourDigits;
   }
private:
   int _AreaCode;
   int _ThreeDigits;
   int _FourDigits;
};

__gc class Employee {
public:
   Employee(String * s, PhoneNumber * p) {
      _name = s;
      _phonenumber = p;
   };

   __property String * get_name() { return _name; }

   __property PhoneNumber * get_number() { return _phonenumber; }

protected:
   String * _name;
   PhoneNumber * _phonenumber;
};

__gc class Manager {
public:
   __property Employee * get_Report(String * s) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> name != s)
         ;
      pEmp = pEmp -> next);
      if (pEmp)
         return pEmp -> emp;
      else
         return 0;
   }
   __property Employee * get_Report(PhoneNumber * p) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> number != p)
         ;
         pEmp = pEmp -> next);
      if (pEmp)
         return pEmp -> emp;
      else
         return 0;
   }

   __property void set_Report(String* s, Employee* e) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> name != s)
         ;
      pEmp = pEmp -> next);
      if (!pEmp)
      {
         EmpList * emp1 = new EmpList; 
         emp1 -> emp = e; 
         emp1 -> next = Reports; 
         Reports = emp1;
      }
   }
   /*   Employee* Report[ String* ]; */       // pseudo array member

   __property void set_Report(PhoneNumber * p, Employee* e) {
      for (pEmp = Reports ; pEmp && (pEmp -> emp -> number != p)
         ;
      pEmp = pEmp -> next);
      if (!pEmp) {
         EmpList * emp1 = new EmpList; 
         emp1 -> emp = e; 
         emp1 -> next = Reports; 
         Reports = emp1;
      }
   };

private:
   __gc struct EmpList {
      Employee * emp;
      EmpList * next;
   };

   EmpList * pEmp;
   static EmpList * Reports = 0;
};

int main() {
   Manager*  Ed = new Manager;
   PhoneNumber * p1 = new PhoneNumber(425, 555, 1111);
   PhoneNumber * p2 = new PhoneNumber(206, 555, 1111);
   Employee* Bob = new Employee(S"Bob Smith", p1); 
   Employee* Gus = new Employee(S"Gus Jones", p2);

   // track Ed's reports
   Ed->Report[ Bob->name ] = Bob;   // indexed by String*
   Ed->Report[ Gus->number ] = Gus;   // indexed by PhoneNumber*
   Console::WriteLine(Ed->Report[ Bob->number ] -> name);
}

Output

Bob Smith
Page view tracker