2011-11-29 11 views
10

Sto usando una libreria di terze parti delphi di grandi dimensioni senza codice sorgente, questa libreria ha diverse classi con metodi astratti. Ho bisogno di determinare quando un metodo di abtract è implementato da una classe Descendant in runtime per evitare lo EAbstractError: Abstract Error e mostra un messaggio personalizzato all'utente o usa invece un'altra classe.Come posso determinare se un metodo astratto è implementato?

ad esempio in questo codice Voglio verificare in runtime se è implementato lo MyAbstractMethod.

type 
    TMyBaseClass = class 
    public 
    procedure MyAbstractMethod; virtual; abstract; 
    end; 

    TDescendantBase = class(TMyBaseClass) 
    public 
    end; 

    TChild = class(TDescendantBase) 
    public 
    procedure MyAbstractMethod; override; 
    end; 

    TChild2 = class(TDescendantBase) 
    end; 

Come è possibile determinare se un metodo astratto è implementato in una classe Descendant in runtime?

risposta

10

è possibile utilizzare Rtti, la funzione GetDeclaredMethods ottiene un elenco di tutti i metodi dichiarati nel tipo riflesso (corrente). Quindi puoi verificare se il metodo è presente nella lista restituita da questa funzione.

function MethodIsImplemented(const AClass:TClass;MethodName : string): Boolean; 
var 
    m : TRttiMethod; 
begin 
    Result := False; 
    for m in TRttiContext.Create.GetType(AClass.ClassInfo).GetDeclaredMethods do 
    begin 
    Result := CompareText(m.Name, MethodName)=0; 
    if Result then 
    break; 
    end; 
end; 

o è possibile confrontare la proprietà Parent.Name del TRttiMethod e verificare se match con il nome della classe corrente.

function MethodIsImplemented(const AClass:TClass;MethodName : string): Boolean; 
var 
    m : TRttiMethod; 
begin 
    Result := False; 
    m:=TRttiContext.Create.GetType(AClass.ClassInfo).GetMethod(MethodName); 
    if m<>nil then 
    Result:=CompareText(AClass.ClassName,m.Parent.Name)=0; 
end; 
4

Guardate l'attuazione del metodo TStream.Seek() nel codice sorgente VCL. Esegue un tipo simile di controllo overriden discendente come si sta cercando, e non comporta ricerche TRttiContext per farlo, solo un semplice ciclo attraverso le sue voci vtable padre/figlio.

4
function ImplementsAbstractMethod(AObj: TMyBaseClass): Boolean; 
type 
    TAbstractMethod = procedure of object; 
var 
    BaseClass: TClass; 
    BaseImpl, Impl: TAbstractMethod; 
begin 
    BaseClass := TMyBaseClass; 
    BaseImpl := TMyBaseClass(@BaseClass).MyAbstractMethod; 
    Impl := AObj.MyAbstractMethod; 
    Result := TMethod(Impl).Code <> TMethod(BaseImpl).Code; 
end; 
+0

Grazie, ma se si utilizza in questo modo ho bisogno di implementare una funzione per ogni tipo di classe e preforo una soluzione più generale. – Salvador

+0

Non sono sicuro che il tuo codice sia corretto. 'ImplementsAbstractMethod (TChild2.Create)' restituirà true, ma né 'TChild2', né' TDescendantBase' hanno sovrascritto l'astratto 'MyAbstractMethod' di' TMyBaseClass'. http://pastebin.com/JufNPJkg –

+0

@rinntech: Grazie per l'avviso. Ho aggiornato la risposta con il codice corretto. –

Problemi correlati