1 de junho de 2012

Trabalhando com informações sobres tipos no Delphi em tempo de execução - parte I

Em muitas situações num programa é conveniente saber o tipo de dado exato com o qual uma rotina está trabalhando, principalmente quando envolve objetos complexos. Dependendo do cenário, é preciso tomar uma decisão baseada no tipo e acessar propriedades e métodos do tipo específico.

Imagine, por exemplo, que você queira garantir que os textos nas telas do seu sistema sejam exibidos usando uma fonte predeterminada. Ao invés de ajustar o fonte manualmente em cada componente da tela, podemos percorrer a lista de componentes e automatizar o ajuste:
procedure TForm1.FormCreate(Sender: TObject);
var i : integer;
lLabel : TLabel;
begin
for i := 0 to ComponentCount - 1 do
if (Components[i] is TLabel) then begin
lLabel := Components[i] as TLabel;
lLabel.Font.Name := 'Calibri';
lLabel.Font.Color := clBlue;
lLabel.Font.Size := 10;
end;
end;
O código acima percorre a lista de componentes da tela e usa a palavra chave IS para saber se o componente atual é do tipo TLabel (ou uma herança dessa classe). Em caso positivo, é feito um cast usando o AS e, então, as propriedades relacionadas ao fonte podem ser configuradas à vontade.

O recurso de uma linguagem de programação que permite obter informações sobre tipos de dados em tempo de execução é chamado de RTTI (Run Time Type Information). Em alguns ambientes, isso também é chamado de Reflexion.

Todos os objetos em Delphi conseguem reportar informações básicas sobre si mesmos, como o nome da classe a que pertencem, de qual classe ela herda, se implementa um determinado método, entre outros.

No entanto, a versão 2010 do Delphi passou por uma grande reformulação no tratamento de RTTI, aumentando significativamente sua capacidade. Agora você também pode obter informações sobre tipos atômicos, além de poder levantar os métodos e propriedades de classes, mesmo aqueles que sejam protegidos ou privados. Também é possível personalizar o RTTI, disponibilizando outras informações e funcionalidades a classes Delphi.

O novo mecanismo é baseado no conceito de "contexto", que nada mais é que o escopo constituido pelo programa principal, as bibliotecas (DLLs) e pacotes agregados. Toda aplicação Delphi passa a ter um único contexto RTTI onde são lançadas as informações sobre os tipos de dados em uso. Com isso, o primeiro passo para se obter informações sobre tipos é declarar e instanciar um contexto.
var lContexto: TRttiContext;
lType: TRttiType;
lMetodo : TRttiMethod;
lParm : TRttiParameter;
begin
lContexto := TRttiContext.Create;
lType := lContexto.GetType(TypeInfo (TForm1));

for lMetodo in lType.GetMethods() do begin
ListBox1.AddItem(lMetodo.Name, lMetodo);
for lParm in lMetodo.GetParameters () do
ListBox1.AddItem(' ' + lParm.ToString (), lParm);
end;

lContexto.Free;
end;
Após instanciar o contexto, esse trecho de código obtém informações sobre o Form atual em dois passos. No primeiro, a função TypeInfo retorna um ponteiro para as informações básicas. Então, o ponteiro é usado num segundo passo para obter as informações extendidas que foram introduzidas na nova versão do RTTI e que são representadas pela classe TRttiType.

Em seguida, o código percorre a lista de métodos do Form1 - incluindo toda a hierarquia de classes a qual ele pertence - e adiciona seus nomes num list box para exibição. Para cada método também é recuperada a lista dos parâmetros que devem ser passados quando ele for chamado em seu programa.

Embora não esteja representado no exemplo, o mesmo tipo de levantamento pode ser feito com as propriedades, ainda que elas não estejam declaradas como published.

A dúvida mais frequente sobre esse tipo de recurso é: em que situações isso pode ser aplicado ? Além do cenário citado no início do post, outras situações podem ser mais facilmente resolvidas com RTTI, tais como a clonagem de objetos (incluindo o estado completo dele), serialização de objetos (transformá-los em um XML ou enviá-los para a impressora, por exemplo), criação de uma infraestutura para aceitar plugins em uma aplicação, chamada dinâmica de métodos, etc.

O próprio IDE do Delphi usa aspectos do RTTI para poder trabalhar com as classes e Forms que você desenvolve, fornecendo informações, por exemplo, para o Code Insight ou serializando a estrutura do Form em um arquivo DFM.

No próximo post, mostro o recurso que permite incrementar as informações de runtime em classes, métodos e propriedades.

Mais Informações
Working with RTTI

Nenhum comentário :

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.