mercredi 7 octobre 2009

Enumérer les méthodes d'une classe (en Run-Time)

L'article "Class RTTI" offre une introduction intéressante à l'utilisation des informations RTTI, HostScripting et de l'invocation automatique des méthodes depuis les WebSnap.

L'utilisation de {$METHODINFO ON} avec l'unité DetailedRtti.pas de David Glassborrow permet d'envisager l'extraction et l'utilisation des informations RTTI en RunTime pour faire des appels dynamiques.
Fournit sous forme de Class  Helper et Record Helper, DetailedRtti.pas permet, par exemple, d'extraire la définition des méthodes/fields/etc d'une classe.

L'exemple ci-dessous énumère toutes les méthodes d'un object.
type 
    {$METHODINFO ON}
  TFRM_Main = class(TForm)
    SBB_Button1: TButton;
    ...

procedure TFRM_Main.Button1Click(Sender: TObject);
begin
  Log( self.RTTIMethodsAsString );
end;


L'énumération des méthodes peuvent s'avérée utile lors de l'invocation sur à la volée (par exemple à l'aide de MethodAddress).
type   TTestProc = procedure of object;
  {$METHODINFO ON}
  TForm1 = class(TForm)
        SBB_DoTesting: TButton;
    ...
  published
    procedure Proc_TestMe;
    procedure Proc_TestMeAlso;
  end;
  ...

procedure TForm1.RunThis(aProcedureName: String);
var
  pProc : TTestProc;
begin
  ShowInfo( 'Executer la méthode '+aProcedureName );
  TMethod(pProc).Data := Self;
  TMethod(pProc).Code := MethodAddress( 'proc_'+aProcedureName);

  try
    if not Assigned(TMethod(pProc).Code) then
      raise Exception.Create( 'Failed to locate test "proc_'+aProcedureName+'" method address' );
    pProc();
  except
    on e:Exception do
      ShowError( E.Message+' ('+E.ClassName+')' );
  end;
end;
... 
procedure TForm1.SBB_DoTestingClick(Sender: TObject);
begin
  // Exemple d'appel dynamique (à partir du nom de la méthode) 

  RunThis( 'TestMe' );
  RunThis( 'TestMeAlso' );
end;
...

Aucun commentaire: