Индексные свойства

Индексные свойства ведут себя аналогично полям-массивам и используются, как правило, для доступа к элементам контейнеров. Как и при использовании обычных свойств, при использовании индексных свойств могут попутно выполняться некоторые действия.

Индексное свойство описывается в классе следующим образом:

property Prop[описание индексов]: тип read IndexedPropertyReader write IndexedPropertyWriter;

В качестве IndexedPropertyReader может выступать:

В качестве IndexedPropertyWriter может выступать:

Функция чтения и процедура записи должны быть методами этого класса и иметь следующий вид:

function GetProp(описание индексов): тип;
procedure
SetProp(описание индексов; value: тип);

В простейшем случае одного индекса описание индексного свойства выглядит так:

property Prop[ind: тип индекса]: тип read GetProp write SetProp;

Всякий раз, когда мы для объекта a, содержащего свойство Prop, выполняем присваивание a.Prop[ind] := value, вызывается процедура a.SetProp(ind,value), а когда считываем значение a.Prop[ind], вызывается функция a.GetProp(ind).

Индексное свойство, после которого добавлено ключевое слово default с последующей ;, называется индексным свойством по умолчанию и позволяет пользоваться объектами класса как массивами, т.е. использовать запись a[ind] вместо a.Prop[ind].

Принципиальное отличие индексных свойств от полей-массивов состоит в том, что тип индекса может быть произвольным (в частности, строковым). Это позволяет легко реализовать так называемые ассоциативные массивы, элементы которых индексируются строками.

В следующем примере индексное свойство используется для закрашивания клеток шахматной доски белым или в графическом режиме.

uses GraphWPF;
const
  n = 8;
  sz = 50;
type
  ChessBoard = class
  private
    a: array [,] of boolean := new boolean[n,n];
    procedure setCell(x,y: integer; value: boolean);
    begin
      if value then
        Brush.Color := Colors.White
      else Brush.Color := Colors.Gray;
      FillRectangle((x-1)*sz+1,(y-1)*sz+1,sz,sz);
      a[x-1,y-1] := value;
    end;
    function getCell(x,y: integer) := a[x-1,y-1];
  public
    property Cells[x,y: integer]: boolean read getCell write setCell; default;
end;

var c: ChessBoard := new ChessBoard;

begin
  for var x:=1 to n do
  for var y:=1 to n do
    c[x,y] := Odd(x+y);
end.

Можно не писать отдельные методы getCell и setCell для доступа к свойству на чтение и запись, а воспользоваться расширенными индексными свойствами:

type
  ChessBoard = class
  private
    a: array [,] of boolean := new boolean[n,n];
  public
    property Cells[x,y: integer]: boolean
      read
a[x-1,y-1]
      write
begin
        if value then
          Brush.Color := Colors.White
        else Brush.Color := Colors.Gray;
        FillRectangle((x-1)*sz+1,(y-1)*sz+1,sz,sz);
        a[x-1,y-1] := value;
      end; default;
end;