O recurso de generics é recente até mesmo no Object Pascal do Delphi, surgiu no Delphi 2009 (meados de 2008). No Free Pascal está presente a partir da versão 2.3.1 (fim de 2007).
Aqui começaremos a ver como trabalhar com listas de objetos mesmo. Não temos mais uma classe de item (com suas propriedades) que é propriedade de uma coleção - temos nosso objeto autônomo e com sua identidade própria, podemos instanciá-lo e usá-lo individualmente ou então fazer uma lista com vários desses objetos. Outro grande lance é que essa lista não recebe um único tipo de objeto, ela pode armazenar qualquer tipo de objeto que descenda da classe desse objeto base (não iremos estender pra isso, mas é daí uma explicação pro termo "generics", podemos fazer listas de qualquer tipo de objeto, colocar nela não só objetos do tipo pré-definido na declaração mas também seus descendentes, enquanto na coleção só tínhamos lista de um único tipo de objeto, o TCollectionItem).
Então vamos começar pela classe dos objetos a serem listados. Como nosso exemplo é uma simples agenda, a classe é uma classe simples cujas propriedades são os campos de cada objeto que é um registro (uma pessoa na agenda). Também nem precisa implementar métodos pra essa classe, ela só tem mesmo propriedades declaradas.
{ TAgendaTelefonicaObj }
TAgendaTelefonicaObj = class
private
FCodigo: Integer;
FNome: String;
FTelefone: String;
public
property Codigo: Integer read FCodigo;
property Nome: String read FNome write FNome;
property Telefone: String read FTelefone write FTelefone;
end;
O próximo passo é criar a lista. Eu dei um nome a ela dentro do contexto e implementei um método e uma função semelhante ao que foi feito no exemplo da coleção pra manipular a inserção e a deleção de objetos da lista, mas no geral isso não seria necessário, mesmo assim, uma vez que a lista é genérica, se os métodos forem 'genéricos' essa mesma declaração de lista poderia ser aproveitada pra mais de um tipo de objetos além do esquema pai/descendentes, pois na verdade na declaração ela não sabe que tipo de objetos vai receber.
{ TAgendaTelefonicaGeneric }
generic TAgendaTelefonicaGeneric = class(TList)
public
function Add(Item: T): Integer;
procedure DeleteByCodigo(Codigo: Integer);
end;
Como dito acima, a exemplo da coleção, manipulamos a função Add pra gerar o nosso código interno do registro automaticamente e temos o método DeleteByCodigo que localiza o objeto pela respectiva propriedade e o deleta da lista. Note que como a lista é genérica na hora de manipular os itens dela (nossos objetos) precisamos fazer uso de typecast pra ter acesso às propriedades deles.
function TAgendaTelefonicaGeneric.Add(Item: T): Integer;var
I: Integer;
begin
//Pega a propriedade código do último objeto
//e incrementa pra obter o código pro novo
if Count = 0 then
TAgendaTelefonicaObj(Item).FCodigo := 1
else
begin
for I := 0 to Count - 1 do
TAgendaTelefonicaObj(Item).FCodigo := TAgendaTelefonicaObj(Items[I]).Codigo + 1;
end;
//Insere
Result := inherited Add(Item);
end;
procedure TAgendaTelefonicaGeneric.DeleteByCodigo(Codigo: Integer);
var
I: Integer;
begin
for I := 0 to Count - 1 do
if TAgendaTelefonicaObj(Items[I]).Codigo = Codigo then
begin
Delete(I);
Break;
end;
end;
Para usarmos em nosso programa entra a última parte da declaração, que a classe que será instanciada e que no tipo especifica a nossa lista genérica. É uma única linha:
TAgendaTelefonicaListaGeneric = specialize TAgendaTelefonicaGeneric;
E daí lá no programa temos então temos como propriedade uma AgendaTelefonicaLista do tipo TAgendaTelefonicaListaGeneric que será de fato a lista usada. No método pra inserir declaramos uma var AgendaTelefonica do tipo TAgendaTelefonicaObj (lembra, o nosso objeto base). Não iremos mais passar valores pra um novo item como na coleção, iremos inserir na lista um objeto já existente.
AgendaTelefonica := TAgendaTelefonicaObj.Create();
AgendaTelefonica.Nome := LabeledEdit1.Text;
AgendaTelefonica.Telefone := LabeledEdit2.Text;
AgendaTelefonicaLista.Add(AgendaTelefonica);
Pra deletar a chamada do método customizado é igual ao da coleção.
AgendaTelefonicaLista.DeleteByCodigo(15);
E num exemplo de exibição da lista de objetos numa ListView semelhante ao que foi dito sobre a coleção temos:
for I := 0 to AgendaTelefonicaLista.Count - 1 do
begin
Item := ListView1.Items.Add();
Item.Caption := IntToStr(TAgendaTelefonicaObj(AgendaTelefonicaLista.Items[I]).Codigo);
Item.SubItems.Add(TAgendaTelefonicaObj(AgendaTelefonicaLista.Items[I]).Nome);
Item.SubItems.Add(TAgendaTelefonicaObj(AgendaTelefonicaLista.Items[I]).Telefone);
end;