Júnior Oliveira

C Sharp; Delphi; ASP .NET; PHP; Javascript;

RTTI (Run-Time Type Information) no Delphi

31 Jul 2010 delphi, rtti

RTTI (Run-Time Type Information) é uma técnica utilizada para identificar tipo de objetos armazenados em memória em tempo de execução.

Abaixo um exemplo de como utilizar RTTI em sua aplicação, este exemplo é apenas uma idéia de como usar RTTI para criar classes e métodos genêricos de acesso a base de dados.

O primeiro código é de uma classe genêrica de modelo da estrutura da tabela no banco de dados. Note que a mesma herda da classe TPersistent pois nela existe as directivas de compilação {$M+} ({$METHODINFO ON}) e {$M-} ({$METHODINFO OFF}) necessárias para implementar o acesso dos dados em memória.

 1 type
 2   TModel = class(TPersistent)
 3     private
 4       { Private declarations }
 5 
 6     public
 7       { Public declarations }
 8       constructor Create(); virtual;
 9       destructor Destroy(); override;
10 
11   end;

O segundo código é de uma classe de modelo da estrutura da tabela Pessoa do banco de dados, note que ela herda a classe TModel e que suas propridades estão declaradas na sessão published pois assim é possível acessa-lás em tempo de execução.

 1 type
 2   TModelPessoa = class(TModel)
 3     private
 4       { Private declarations }
 5       FPessIden: Integer;
 6       FPessNome: String;
 7 
 8     public
 9       { Public declarations }
10       constructor Create(); override;
11       destructor Destroy(); override;
12 
13     published
14       { Published declarations }
15       property PessIden: Integer read FPessIden write FPessIden;
16       property PessNome: String read FPessNome write FPessNome;
17 
18   end;

O terceiro código é de uma classe teria os métodos de operação na base de dados porém eu retirei pois este não é o foco deste post e sim apenas mostrar uma utilização do RTTI. Então vamos a explicação, o método fillProperty é responsável por verificar as propriedades do objeto do tipo ou que herde a classe TModel passado por parâmetro. Outro detalhe importante é a declaração da unit TypInfo que contém os métodos responsáveis em acessar os dados em memória.

 1 uses
 2   TypInfo, Dialogs, Classes, Model;
 3 
 4 type
 5   TController = class(TObject)
 6     private
 7       { Private declarations }
 8 
 9     public
10       { Public declarations }
11       constructor Create(); virtual;
12       destructor Destroy(); override;
13       procedure fillProperties(model: TModel);
14 
15   end;

Como descrito anteriomente o método responsável por acessar os dados em memória do objeto em tempo de execução. Note que após o termino do for foi inserido um ShowMessage(msg.Text); para informar ao usuário as propriedades e o valor das propriedades do objeto passado por parâmetro.

 1 procedure TController.fillProperties(model: TModel);
 2 var
 3   listProp: PPropList;
 4   listPropCount, i: Integer;
 5   propInfo: TPropInfo;
 6   valueProp: Variant;
 7   msg: TStringList;
 8 begin
 9   {Obtem informacoes dos atributos que sao Publisheds}
10   listPropCount:= GetPropList(model.ClassInfo, tkAny, nil);
11   GetMem(listProp, listPropCount * SizeOf(TPropInfo));
12 
13   try
14     msg:= TStringList.Create();
15 
16     GetPropList(model, listProp);
17     for i:= 0 to Pred(listPropCount) do
18     begin
19       {Obtem informacoes da propriedade}
20       propInfo:= TPropInfo(listProp^[i]^);
21       valueProp:= GetPropValue(model, propInfo.Name);
22 
23       msg.Add(Format('%s: %s;', [propInfo.Name, valueProp]));
24     end;
25 
26     ShowMessage(msg.Text);
27   finally
28     FreeAndNil(msg);
29     FreeMem(listProp);
30   end;
31 end;

E por fim um trecho de código para você adicionar ao evento de um button por exemplo de como utilizar o método fillProperties da classe TController.

 1 var
 2   modelPessoa: TModelPessoa;
 3   controller: TController;
 4 begin
 5   try
 6     modelPessoa:= TModelPessoa.Create();
 7     controller := TController.Create();
 8     modelPessoa.PessIden:= StrToInt(self.edtPessIden.Text);
 9     modelPessoa.PessNome:= self.edtPessNome.Text;
10 
11     controller.fillProperties(modelPessoa);
12   finally
13     FreeAndNil(modelPessoa);
14     FreeAndNil(controller);
15   end;
16 end;

Espero que gostem e seja útil de alguma forma este exemplo. Em breve estárei postando uma aplicação mais real da utilização do RTTI para criação de classes e métodos genêricos de acesso a dados, lembrando que este não é a única utilização do RTTI.

Desde já agredeço a visita.