|
Usuários |
|
80 Usuários Online
|
|
[Artigos]
Conhecendo um pouco da RTTI. Parte II |
Publicado por rboaro : Quarta, Dezembro 19, 2012 - 11:44 GMT-3 (372 leituras)
comentar Enviar para um amigo Versão para impressão
|
Dando continuidade aos estudos sobre a poderosa RTTI do Delphi, como eu havia prometido na primeira parte do artigo, vamos nos aprofundar um pouco mais no TRttiContext no TRttiType e no TRttiField.
- TRttiContext: O TRttiContext é praticamente a parte principal da RTTI, é através dele que se torna possível ter acesso aos métodos e atributos de um objeto em tempo de execução. Como vimos no post anterior, foi através dele que obtivemos toda estrutura do nosso objeto, utilizando o método GetType().
var
ctxRtti : TRttiContext;
typRtti : TRttiType;
begin
typRtti := ctxRtti.GetType(objeto.ClassType);
- TRttiType: O TRttiType por sua vez armazena as informações que foram obtidas com o método GetType do TRttiContext. A partir do momento em que foram armazenadas as informações do type do objeto em um TRttiType é possível acessar qualquer informação deste objeto.
- TRttiField: O TRttiField é responsável por armazenar informações sobre um campo recuperado através de um TRttiType. Com o TRttiField é possível recuperar informações como o nome do campo e seu tipo e até mesmo manipular o valor armazenado neste campo em uma instancia qualquer do objeto em questão.
Para deixar as coisas um pouco mais interessantes, vamos fazer um exemplo prático, primeiramente vamos fazer um método para listar todos os campos disponíveis em um objeto
procedure pegarListaCamposRttiObj(classe: TClass;
linhasRetorno: TStrings);
var
fldRtti: TRttiField;
typRtti: TRttiType;
ctxRtti: TRttiContext;
begin
ctxRtti := TRttiContext.Create;
try
typRtti := ctxRtti.GetType(classe);
for fldRtti in typRtti.GetFields do
linhasRetorno.Add(fldRtti.Name + '<' + fldRtti.FieldType.ToString + '>');
finally
ctxRtti.Free;
end;
end
Agora vamos fazer um método que recupere um TRttiField através do nome do campo
function retornarRttiField(ctxRtti : TRttiContext; classe: TClass; const nomeCampo: String): TRttiField;
var
typRtti : TRttiType;
begin
typRtti := ctxRtti.GetType(classe);
Result := typRtti.GetField(nomeCampo);
end;
Vale ressaltar que este método retornará NIL caso não seja encontrado nenhum campo com o nome passado no parâmetro nomeCampo.
Para finalizar vamos fazer um método para recuperar o valor armazenado neste campo e um método para atribuir um valor qualquer neste campo.
function retornarValorRttiField(objeto : TObject;
const nomeCampo: String): TValue;
var
ctxRtti : TRttiContext;
retorno : TValue;
begin
retorno := nil;
ctxRtti := TRttiContext.Create;
try
try
retorno := retornarRttiField(ctxRtti,objeto.ClassType,nomeCampo).GetValue(objeto);
except
retorno := nil;
end;
finally
ctxRtti.Free;
Result := retorno;
end;
end;
procedure TForm1.setarValorRttiField(objeto: TObject; const nomeCampo : string;
const valor: TValue);
var
ctxRtti : TRttiContext;
begin
ctxRtti := TRttiContext.Create;
try
try
retornarRttiField(ctxRtti,objeto.ClassType,nomeCampo).SetValue(objeto,valor);
except
end;
finally
ctxRtti.Free;
end;
end;
Agora vamos finalmente testar nossos métodos, vamos criar uma classe para realizar o teste.
type
TTesteRtti = class
private
FCampoString : string;
FCampoReal : real;
FCampoBoolean : boolean;
FCampoDate : TDate;
published
property campoString : string read FCampoString write FCampoString;
property campoReal : real read FCampoReal write FCampoReal;
property campoBoolean : boolean read FCampoBoolean write FCampoBoolean;
property campoDate : TDate read FCampoDate write FCampoDate;
end;
Depois, para deixar nosso teste ?mais visual? vamos fazer um form com um EDIT, três BUTTONS, um LISTBOX e um LABEL. No onCreate do Form, crie uma instancia da nossa classe de teste e libere ela no onClose do Form. Em um dos Buttons vamos povoar nosso ListBox com os campos da nossa classe
pegarListaCamposRttiObj(objTesteRtti.ClassType,ListBox1.Items);
Em outro Button, vamos fazer a rotina para setar o valor do Edit em um campo selecionado no ListBox, note que será necessário realizar alguns casts devido ao fato de estarmos trabalhando com String no Edit.
var
valor : TValue;
nomeCampo : string;
tipoCampo : string;
begin
nomeCampo := ListBox1.Items.Strings[ListBox1.ItemIndex];
nomeCampo := Copy(nomeCampo,1,Pos('<',nomeCampo) - 1);
tipoCampo := ListBox1.Items.Strings[ListBox1.ItemIndex];
tipoCampo := Copy(tipoCampo,pos('<',tipoCampo) + 1);
tipoCampo := Copy(tipoCampo,1,length(tipoCampo) -1);
if UpperCase(tipoCampo) = 'STRING' then
valor := TValue.FromVariant(Edit1.Text)
else if UpperCase(tipoCampo) = 'TDATE' then
valor := TValue.FromVariant(StrToDate(Edit1.Text))
else if UpperCase(tipoCampo) = 'BOOLEAN' then
valor := TValue.FromVariant(StrToBool(Edit1.Text))
else if UpperCase(tipoCampo) = 'REAL' then
valor := TValue.FromVariant(StrToFloat(Edit1.Text));
setarValorRttiField(objTesteRtti,nomeCampo,valor);
Para finalizar, vamos fazer no Button que sobrou a rotina para recuperar o valor do campo selecionado no ListBox
var
nomeCampo : string;
begin
nomeCampo := ListBox1.Items.Strings[ListBox1.ItemIndex];
nomeCampo := Copy(nomeCampo,1,Pos('<',nomeCampo) - 1);
Label1.Caption := retornarValorRttiField(objTesteRtti,nomeCampo).ToString;
Pronto, agora nosso teste já está pronto, bastar executá-lo e ir adaptando o conceito de acordo com a sua necessidade.

Um detalhe importante é que ao invés de trabalhar com os campos da classe, poderíamos trabalhar com suas Propertys, basta substituir o TRttiField pelo TRttiProperty.
Na próxima parte do estudo veremos um pouco sobre o TRttiMethod e como poderemos invocar métodos dinamicamente, inclusive com passagem de parâmetro.
|
|
Comentários | |
| | Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos. |
|
|
Edição 112 |
|
|
50 Programas Fontes |
|
|
Produtos |
|
|