Jeśli istnieją ograniczenia związane z liczbą indeksów w właściwości indeksowanej, to są to ograniczenia związane z liczbą parametrów zwykłej metody. Pewnie jakieś istnieją, ale jest to liczba dość duża, której w zwykłym kodzie się raczej nie osiągnie. No bo kto by potrzebował metody przyjmującej np. 50 parametrów? ;)
Przykład:
type
TSome = class(TObject)
private
function GetFoo(A, B, C, D, E, F, G: Integer): Integer;
procedure SetFoo(A, B, C, D, E, F, G: Integer; AValue: Integer);
public
property Foo[A, B, C, D, E, F, G: Integer]: Integer read GetFoo write SetFoo;
end;
Użycie takiej właściwości:
var
Some: TSome;
begin
Some := TSome.Create();
Some.Foo[0, 1, 2, 3, 4, 5, 6] := 100;
Jak widać, właściwość indeksowana siedmioma wartościami może istnieć (sens jej istnienia to inna bajka). Tutaj warto zaznaczyć, że indeksy właściwości indeksowanej nie mają nic wspólnego z wymiarami. Można powiedzieć, że właściwość Foo
jest jedynie krótkim wrapperem na metody GetFoo
i SetFoo
, a nawet cukrem składniowym, a jej indeksy to po prostu parametry tych metod. Tak więc aby móc korzystać z takiej właściwości, nie musisz mieć wielowymiarowej macierzy, z której czyta getter i którą modyfikuje setter.
Druga sprawa to typy danych parametrów indeksowanej właściwości. Nie muszą to być indeksy tego samego typu, bo tak jak napisałem wyżej, właściwość indeksowana to tylko wrapper na konkretne metody. Skoro metoda może posiadać parametry różnego typu, to i właściwość może przyjmować indeksy różnego typu.
Drugi przykład:
type
TSome = class(TObject)
private
function GetFoo(A: Integer; B: Boolean; C: String; D: TClass): Double;
procedure SetFoo(A: Integer; B: Boolean; C: String; D: TClass; AValue: Double);
public
property Foo[A: Integer; B: Boolean; C: String; D: TClass]: Double read GetFoo write SetFoo;
end;
Indeksy właściwości są cztery, każdy innego typu – nie ma problemu. I przykładowe wywołanie:
var
Some: TSome;
begin
Some := TSome.Create();
Some.Foo[8, False, 'furious', TStringList] := 3.14;
Parametr indeksowanej właściwości może być też rekordem, a nawet macierzą (a co!):
type
TCaptions = array of String;
type
TSome = class(TObject)
private
function GetFoo(A: String; const B: TCaptions): Double;
procedure SetFoo(A: String; const B: TCaptions; AValue: Double);
public
property Foo[A: String; const B: TCaptions]: Double read GetFoo write SetFoo;
end;
Przykład użycia:
var
Some: TSome;
begin
Some := TSome.Create();
Some.Foo['furious', TCaptions.Create('foo', 'bar', 'baz')] := 3.14;
Do tej pory trzeba było pisać nazwę właściwości – tu: Foo
– aby móc z niej skorzystać. Żeby tego nie robić, wystarczy dodać słówko default
na końcu deklaracji właściwości, np.:
property Foo[A, B, C, D, E, F, G: Integer]: Integer read GetFoo write SetFoo; default;
Dzięki temu nawiasy do podawania indeksów mogą teraz być pisane tuż po identyfikatorze zmiennej:
var
Some: TSome;
begin
Some := TSome.Create();
Some[0, 1, 2, 3, 4, 5, 6] := 100;
Należy pamiętać, że tylko jedna właściwość w klasie może być domyślną, a także o tym, że default
ma więcej znaczeń, co zależy od kontekstu. Dzięki niemu możliwe jest też definiowanie domyślnej wartości parametru metody czy właściwości upublicznionej (co ma związek z zasobami formularzy, ale nie ma związku z problemem poruszanym w tym wątku, więc o tym kiedy indziej).
Można powiedzieć, że właściwości w obiektowym Pascalu są jednymi z najbardziej (jeśli nie najbardziej) rozbudowanymi i funkcjonalnymi konstrukcjami spośród wszystkich języków programowania. Indeksowanie właściwości to tylko jedna z wielu fajnych i przydatnych rzeczy – jest jeszcze wiele innych ciekawych konstrukcji.
Trzeba jednak pamiętać, że rozbudowane właściwości są możliwością, a nie koniecznością. Nikt nie lubi skoplikowanego kodu, więc należy unikać przesadyzmu.