Saturday, 12 September 2009

más sobre la RTTI de Delphi 2010

Hoy, tocando un poco mas la nueva RTTI de delphi, he encontrado algo similar a la inyección de parámetros! Brutal!. Éstos no están disponibles en tiempo de diseño, pero si que los podemos capturar mediante el uso de la API de la RTTI. De ésta manera, nos permite asignar una série de atributos a nuestros métodos, pero no solo eso, también lo podremos hacer también con propiedades, clases, etc. En éste pequeño ejemplo que os pongo, adaptado del ejemplo que ha hecho Malcolm Groves en su gran explicación sobre los atributos de la RTTI, añado una serie de atributos a unos métodos y luego los recupero con la RTTI API.

En el ejemplo, crearé un objeto que hereda de TCustomAttribute:
The base class for all custom attributes. Attribute instances created by the RTTI unit are owned by those members to which they apply.
Ésta clase es la que tenemos que utilizar para manejar nuestros atributos, por lo tanto si miramos la creación de un atributo personalizado:


type
MyCustomAttribute = class(TCustomAttribute)
private
FId: Integer;
FDescription: string;
public
constructor Create(Id: Integer; const Description: string);
property Id: Integer read FId write FId;
property Description: string read FDescription write FDescription;
end;

{ MyCustomAttribute }

constructor MyCustomAttribute.Create(Id: Integer; const Description: string);
begin
FId := Id;
FDescription := Description;
end;

Ahora que ya tenemos nuestra clase atributo creada, aplicamos éstos atributos a nuestros métodos, de alguna manera me recuerda a la Inyección en Java, ya que solo le indicabas las cosas a inyectar y él se encargaba de la creación de las clases. Pues aquí pasa algo parecido, nosotros solo tenemos que indicar los parámetros y él ya hace la creación:...fabuloso!.


type
TMyCustomClass = class(TObject)
public
[MyCustomAttribute(1, 'Attr1')]
procedure MyProcedure1;
[MyCustomAttribute(2, 'Attr2')]
procedure MyProcedure2;
[MyCustomAttribute(3, 'Attr3')]
procedure MyProcedure3;
end;

{ TMyCustomClass }

procedure TMyCustomClass.MyProcedure1;
begin

end;

procedure TMyCustomClass.MyProcedure2;
begin

end;

procedure TMyCustomClass.MyProcedure3;
begin

end;

Para poder acceder a éstos parámetros, lo único que tenemos que hacer, es realizar la llamada a la famosa RTTI API, mediante los métodos que os puse en el post anterior:


procedure TForm1.LoadAttr(Sender: TObject);
var
ContextRtti: TRttiContext;
RttiType: TRttiType;
RttiMethod: TRttiMethod;
CustomAttr: TCustomAttribute;
begin
Memo1.Clear;
ContextRtti := TRttiContext.Create;
try
RttiType := ContextRtti.GetType(TMyCustomClass);
for RttiMethod in RttiType.GetMethods do
for CustomAttr in RttiMethod.GetAttributes do
if CustomAttr is MyCustomAttribute then
Memo1.lines.Add(Format(
'Method = %s; Attribute = %s, Id = %d, Description = %s',
[RttiMethod.Name, CustomAttr.ClassName, MyCustomAttribute
(CustomAttr).Id, MyCustomAttribute(CustomAttr).Description]));
finally
ContextRtti.Free;
end;
end;

Ahora, con la llamada a éste método, podemos obtener los siguiente:

Bueno, solo nos queda indagar un poco más para ver como podemos explotar ésto aún más y más. Pero por lo visto habrá que mirarse los cambios muy y muy bien.

3 comments:

  1. Hay algun ejemplo que utiliza estos parametros para poner el nombre de la tabla de la BD y de los campos en las propiedades, obteniendo una forma generica de guardar objetos a la BD.

    ReplyDelete
  2. Si consultas el blog de Robert Love puede que encuentres alguna cosa:
    http://robstechcorner.blogspot.com/

    De todas maneras creo que es bastante fácil, simplemente configurando bien los atributos podremos parametrizar todo ésto para que la RTTI guarde información en la BD.

    ReplyDelete
  3. también te puede interesar la siguiente entrada en el blog de Database Connectivity utilizando JSON:
    http://blogs.embarcadero.com/adrian/2009/08/19/json-types-for-server-methods-in-datasnap-2010/

    ReplyDelete