Atenção: esse artigo tem uma palestra complementar. Clique e assista!
Atenção: esse artigo tem um vídeo complementar. Clique e assista!
Explorar o uso dos recursos aprimorados no Delphi 2010, Generics, RTTI e Custom Attributes. Essa exploração se dá na explicação conceitual de cada item, com exemplos inicialmente simples e práticos para posteriormente unir esses recursos e desenvolver algo mais complexo, o mini framework de validação que poderá ser utilizado e reutilizado em vários projetos.
Para que serve
Ao compreender o uso de Generics, RTTI e Custom Attributes, será possível utilizá-los para o desenvolvimento de frameworks que venham agilizar o dia-a-dia. Frameworks que poderão ser reutilizados entre projetos distintos ou mesmo que não se deseje criar um framework, será possível centralizar rotinas básicas como validação, acesso a dados etc.
Em que situação o tema é útil
Para mostrar a utilidade, desenvolvemos um mini framework de validação, contudo seu uso pode ser muito amplo. Com Generics é possível especializar listas como também criar ordenadores de listas. Com RTTI podemos explorar um projeto em tempo de execução, podendo até mesmo executar um método por seu nome, gerando certa flexibilidade ao código. Podemos também adicionar informações em campos, classes, propriedades através dos Custom Attributes.
Resumo do DevMan
Vamos mostrar na prática o uso de três recursos melhorados no Delphi 2010: Generics, RTTI e Custom Attributes. Vamos entender como cada um funciona particularmente e então unir o poder de cada um para o desenvolvimento de um framework de validação. Com esse framework será possível validar se um TEdit pode ser vazio. Se uma quantidade mínima de caracteres foi informada e muito mais, além de poder mostrar isso ao usuário de uma forma elegante.
Vamos construir um pequeno framework de validação que poderá ser utilizado em suas classes e até mesmo nos componentes inseridos em um determinado formulário. Para isso vamos fazer uso dos recursos novos do Delphi 2010: Generics, RTTI e Custom Attributes. Portanto vamos compreender o que são eles.
Generics
A introdução do Generics na linguagem Delphi permite ao desenvolvedor a criação de parâmetros de tipo. Mas o que é isso exatamente? Normalmente quando definimos uma função ou procedimento que receba parâmetros esses são passados como instâncias. Observe o seguinte código:
procedure EscreverNaTela(const Texto: TTextoDeAjuda);
O procedimento EscreverNaTela recebe como parâmetro um objeto do tipo TTextoDeAjuda, ou seja, recebe uma instância dessa classe. Nesse caso é possível passar para o método apenas objetos do tipo esperado ou seus descendentes. Ao utilizarmos Generics é possível passar um tipo como parâmetro, e esse tipo será resolvido em tempo de execução, permitindo que o procedimento seja parametrizado. O mesmo procedimento usando Generics teria a seguinte assinatura:
procedure EscreverNaTela<T>;
Onde T é o tipo de dado. O Delphi já traz em sua estrutura de classes algumas prontas para utilizar Generics. Vamos observar a classe TList<T>, Listagem 1.
Listagem 1. Estrutura da classes TList<T>
type
TList<T> = class(TEnumerable<T>)
// ...
public
// ...
function Add(const Value: T): Integer;
procedure Insert(Index: Integer; const Value: T);
function Remove(const Value: T): Integer;
procedure Delete(Index: Integer);
procedure DeleteRange(AIndex, ACount: Integer);
function Extract(const Value: T): T;
procedure Clear;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
end;
Observe que os métodos foram adaptados para se trabalhar com tipo genérico, permitindo que um TList seja tipado. Antes disso era necessário realizar operações de boxing e unboxing (falaremos mais sobre isso a seguir) para armazenar um tipo específico, o que poderia levar a erros. Para exemplificar isso, vamos construir nosso primeiro exemplo.
Utilizando Generics
Vamos ter uma aplicação VCL Forms, e nela dois botões. Nesse primeiro botão vamos mostrar o uso de um TList comum e no segundo o uso do TList<T>. Crie então a aplicação, insira os dois botões. Logo abaixo da declaração da classe do formulário vamos criar uma classe TPessoa, como mostra Listagem 2.
Listagem 2. Classe TPessoa
TPessoa = class
public
Nome: string;
constructor Create(NomePessoa: string); reintroduce;
function ToString: string; override;
end;
Veja que é uma classe simples. Temos um construtor, uma propriedade e sobrecarregamos o método ToString, que existe originalmente em TObject. Esse método ToString pode ser utilizado para retornar o objeto no formato string, conforme vemos na implementação da classe na Listagem 3.
Listagem 3. Implementando a classe TPessoa
function TPessoa.ToString: string;
begin
result := Nome;
end;
constructor TPessoa.Create(NomePessoa: string);
begin
inherited Create;
Nome := NomePessoa;
end;
Mais uma vez o código é bem simples. No construtor apenas instanciamos o objeto, ao chamar o Create da classe base TObject e em seguida passamos para o campo Nome o valor do parâmetro NomePessoa. Já no método ToString apenas retornamos o valor de Nome.
...