A Delphi programozási nyelv

Sablonok

Delphiben van lehetőség alprogramok paraméterezésére akár függvénnyel is (alprogram típus). Az újabb Delphi verziókban megjelent a generikus típus, amelyet más típusokkal paraméterezhetünk.

Szintaxis

Generikus lehet: alprogram típus, rekord, osztály és interfész típus. A generikus típust úgy deklaráljuk, hogy a neve után <> jelek között felsoroljuk a típusparamétereket.

Fontos: ha a > jel után = következik (típusdeklarációnál mindig így van), akkor a két jel közé szóközt kell tenni, egyébként a fordító a >= karaktersorozatot a „nagyobb vagy egyenlő” operátorként értelmezi.

type TPair<TKey,TValue> = class // TKey és TValue a típusparaméterek FKey: TKey; FValue: TValue; function GetValue: TValue; end; function TPair<TKey,TValue>.GetValue: TValue; begin Result := FValue; end;

Metódus lehet generikus, de különálló alprogram nem.

Paraméterek

Típusparaméterként átadható tetszőleges típus, kivéve fix méretű tömb, rövid string és olyan rekord, amely tartalmaz tiltott típusú mezőt (ez utóbbi kikötés rekurzív).

Példányosítás

Generikus típus példányosításakor a típusparaméterek helyére típusokat írunk.

A példányosítás során új típus (vagy metódus) jön létre. Nincs lehetőség futási idejű példányosításra. Sok példányosítás megnöveli a program méretét.

type TFoo<T> = class FData: T; end; var F: TFoo<Integer>; // Az Integer típus a TFoo aktuális típusparamétere begin ... end.

Generikus metódus példányosítható explicit módon vagy a paraméterekből való kikövetkeztetéssel (ez úgy működik, mint a túlterhelés):

type TMyProc2<Y> = procedure(Param1, Param2: Y) of object; TFoo = class procedure Test; procedure MyProc2<T>(X, Y: T); end; procedure TFoo.MyProc2<T>(X, Y: T); begin WriteLn('MyProc2<T>'); end; procedure TFoo.Test; var P: TMyProc2<Integer>; begin MyProc2<String>('Hello', 'World'); // explicit példányosítás MyProc2('Hello', 'World'); // kikövetkeztetés a paraméter típusából MyProc2<Integer>(10, 20); MyProc2(10, 20); P := MyProc2<Integer>; P(40, 50); end; var F: TFoo; begin F := TFoo.Create; F.Test; F.Free; end.

Tapasztalat: a Delphi 2010 IDE panaszkodik a kikövetkeztetéses hívásoknál, hogy nincs ilyen metódus, viszont a fordító le tudja fordítani.

Megszorítások

A Delphi a szerződésalapú generikus programozást támogatja: a típusparaméterekről csak annyit feltételezhetünk, amennyit megköveteltünk tőlük, példányosításkor pedig gondoskodnunk kell róla, hogy a típusparaméterek teljesítsék ezeket a követelményeket.

A megszorítás szintaxisa hasonló az alprogram-paraméterek típusának megadásához:

type TFoo1<T: ISerializable> = class FField: T; end; TFoo2<T: ISerializable; V: IComparable> ... //2 paraméter különböző megszorításokkal TFoo3<S, U: ISerializable> ... //2 paraméter azonos megszorításokkal TFoo4<T: ISerializable, ICloneable; V: IComparable> ... //T-re két megszorítást adunk, V-re egyet TFoo5<T; C: IComparable> ... //T-re és V-re nincs megszorítás - figyeljünk a TBar<T, V> ... //vessző és a pontosvessző használatára! TTest<S: ISerializable; V> ...

A megszorítások jelentése

Interfész megszorítás

Ha megszorításként egy interfészt adunk meg, akkor az aktuális típusparaméternek meg kell valósítania az interfészt. Mivel Delphiben csak az osztályok és más interfészek valósíthatnak meg interfészt, az interfész megszorítás esetén csak osztály vagy interfész adható át a paraméterben. Egy típusparaméterhez tetszőleges számú interfész megszorítás adható. Ha a megadott interfészek rendelkeznek azonos nevű metódussal, akkor a fordító ezt túlterhelésként kezeli. Előfordulhat, hogy nem lesz egyértelmű a hívás, ilyenkor explicit típuskényszerítéssel oldhatjuk fel a konfliktust.

type TFoo<T: ISerializable, ICloneable> = class FData: T; procedure Test; end; procedure TFoo<T>.Test; begin FData.Clone; //ha az ISerializable és az ICloneable is tartalmaz 0 paraméteres end; //Clone metódust, akkor fordítási hibát kapunk
Osztály megszorítás

Egy típusparaméternek legfeljebb egy osztály megszorítás adható meg. Ha megadjuk, akkor az aktuális paraméternek a megadott osztály leszármazottjának kell lennie.

Konstruktor megszorítás

Megadható megszorításként a constructor kulcsszó. Ilyenkor az aktuális paraméternek rendelkeznie kell Create nevű, paraméter nélküli konstruktorral. Mivel Delphiben csak az osztályoknak lehet paraméter nélküli konstruktora, a konstruktor megszorítás esetén csak osztály adható át a paraméterben.

Érték vs. referencia típus megszorítás

Megadható megszorításként a class vagy a record kulcsszó. Ezek azt kötik ki, hogy a paraméter osztály típus illetve érték szerinti típus. A record megszorítás nem teszi kötelezővé, hogy rekord legyen a paraméter, csak azt, hogy ne legyen referencia típus. (Delphiben az interfész és az osztály a referencia típusok.) class esetén viszont kötelezően osztályt kell megadni. Értelemszerűen a record megszorítás nem kombinálható a többi fajta megszorítással.