2011-11-29 11 views
10

Estoy usando una gran biblioteca de terceros de Delphi sin código fuente, esta biblioteca tiene varias clases con métodos abstractos. Necesito determinar cuándo un método abtract es implementado por una clase Descendant en tiempo de ejecución para evitar el EAbstractError: Abstract Error y muestra un mensaje personalizado para el usuario o usa otra clase en su lugar.¿Cómo puedo determinar si se implementa un método abstracto?

por ejemplo en este código Quiero verificar en tiempo de ejecución si se implementa 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; 

¿Cómo puedo determinar si un método abstracto se implementa en una clase descendiente en tiempo de ejecución?

Respuesta

10

puede utilizar la función Rtti, GetDeclaredMethods obtener una lista de todos los métodos que se declaran en el tipo reflejado (actual). Entonces puede verificar si el método está presente en la lista devuelta por esta función.

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 se puede comparar la propiedad Parent.Name del TRttiMethod y comprobar si partido con el nombre de la clase actual.

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

vistazo a la implementación del método TStream.Seek() en el código fuente VCL. Lleva a cabo un tipo similar de cheque descuido de descendiente como lo que está buscando, y no implica búsquedas TRttiContext para hacerlo, simplemente un bucle simple a través de sus entradas vtable padre/hijo.

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

Gracias, pero si uso de esta manera, necesito implementar una función para cada tipo de clase y prefiero una solución más general. – Salvador

+0

No estoy seguro si su código es correcto. 'ImplementsAbstractMethod (TChild2.Create)' devolverá true, pero ni 'TChild2', ni' TDescendantBase' han anulado el resumen 'MyAbstractMethod' de' TMyBaseClass'. http://pastebin.com/JufNPJkg –

+0

@rinntech: Gracias por el aviso. He actualizado la respuesta con el código correcto. –

Cuestiones relacionadas