19.01.2017, Vladimír Klaus, navštíveno 3748x
Nejprve by bylo asi fajn říci, co to jsou generika, resp. generické datové typy. Je to obecný datový typ, kterému jeho konkrétní podobu přiřadíme až později. Je to tedy vlastně typ s parametrem. Každý známe TStringList, který se používá na seznam stringů. Jenže to je už předpřipravený typ. Kdyby nebyl, tak bychom museli použít nějaký obecný (generický) typ pro seznam a říci mu, že bude obsahovat stringy.
Pokud by byl potřeba seznam integerů, tak nám v podstatě ani nic jiného nezbyde, protože v Delphi nic jako TIntegerList neexistuje. A stejně tak se musí postupovat, pokud budete chtít seznam ještě něčeho složitějšího, třeba nějakého vlastního typu. V takovém případě můžeme začít vymýšlet objekt, jeho metody a vlastnosti od nuly, což by dalo docela dost práce. No a nebo využijeme generický datový typ TObjectList a jen mu sdělíme, co konkrétně do toho seznamu budeme dávat. A všechno ostatní už necháme na něm. Žádné vymýšlení, jak vložit hodnotu, jak ji odstranit, jak smazat vše, jak zjistit počet údajů atd.
Představme si příklad, kdy máte seznam dvojic - množství a tomu odpovídající cena. Je to z praxe, i když to tak třeba nevypadá, ale dá se to použít pro případ, kdy nakupujete nějaké zboží za nějakou jednotkovou cenu. A později stejné zboží za jinou cenu. Nadefinujeme si třídu třeba takto.
uses Generics.Collections;
type
TMnozstviCena = class
Mnozstvi: Real;
Cena: Currency;
end;
A teď přijde na řadu onen generický typ s parametrem. Všimněte si ohraničení parametru špičatými závorkami. Bude to seznam objektů, ale typu, který si sami zadáme, tedy TMnozstviCena.
//musí to být TObjectList, aby se při Free/Clear uvolňovaly i objekty,
//na které to ukazuje
TMnozstviCenaSeznam = class(TObjectList<TMnozstviCena>);
Dále budeme pokračovat normální deklarací proměnných a vytvořením instance pro seznam.
var
SeznamMnozstviCena: TMnozstviCenaSeznam;
MC: TMnozstviCena;
SeznamMnozstviCena:=TMnozstviCenaSeznam.Create;
Připravíme si instanci dvojice a přidáme ji do seznamu.
MC:=TMnozstviCena.Create;
MC.Cena:=100;
MC.Mnozstvi:=65;
SeznamMnozstviCena.Add(MC);
Pokud vás to tady někde bude svádět k MC.Free, tak to rozhodně nedělejte, protože to byste data ze seznamu zase smazali. :-)
Proto může být lepší a nakonec i úspornější sloučit to do jednoho příkazu:
SeznamMnozstviCena.Add(TMnozstviCena.Create(100, 65));
Nicméně to zase vyžaduje doplnit typ o konstruktor:
type
TMnozstviCena = class
Mnozstvi: Real;
Cena: Currency;
constructor Create(aMnozstvi: Real; aCena: Currency);
end;
constructor TMnozstviCena.Create(aMnozstvi: Real; aCena: Currency);
begin
Mnozstvi:=aMnozstvi;
Cena:=aCena;
end;
A až budete seznam potřebovat uvolnit, stačí zavolat FreeAndNil. A protože to je TObjectList, zavolá se Free i na všechny prvky seznamu, takže uvolníme paměť opravdu kompletně, jak od seznamu, tak i jednotlivých položek.
//a seznam vyčistím od pointerů, ale i objektů, na které ukazovaly
FreeAndNil(SeznamMnozstviCena);
Zdá se vám to jednoduché? Ano, to je správně, i složitě pojmenované věci mohou být jednoduché, alespoň v jejich základním a velmi jednoduchém použití. Mnohem více a lépe popsané se dozvíte v e-booku od Marco Cantù "Object Pascal Handbook". K té se jednoduše dostanete po koupení Delphi nebo přímým objednáním z níže uvedeného odkazu. Generikům je tam věnováno 50 stránek a to už za to fakt stojí.
Celá problematika je pochopitelně mnohem rozsáhlejší, ale jak je patrné z názvu tohoto článku, zde jsme si ukázali jen úplné základy pro prvotní pochopení, resp. reálné využití. Generika jsou samozřejmě i v řadě dalších modernějších jazyků, včetně C#, C++, Javy apod. A na tom je skvělá ještě jedna věc - píše se to a používá v podstatě stejně, takže v C# by výše uvedený příklad vypadal asi nějak takto. Uvolňování seznamu nehledejte, o to se zde postará automaticky Garbage collection.
using System.Collections.Generic;
public class MnozstviCena {
public float Mnozstvi;
public decimal Cena;
}
var MnozstviCenaSeznam = new List<MnozstviCena>();
var MC = new MnozstviCena();
MC.Cena = 100;
MC.Mnozstvi = 65;
MnozstviCenaSeznam.Add(MC);
Zdroje: