2009-05-12 17 views
6

¿Es posible en Delphi usar RTTI (u otra cosa) para verificar si una clase se declara como abstracta? Algo así como:¿Cómo comprobar si una clase Delphi se declara abstracta?

TMyAbstractClass = class abstract(TObject) 
    // ... 
end; 

... 

if IsAbstract(TMyAbstractClass.ClassInfo) then 
    ShowMessage('Yeah') 
else 
    ShowMessage('Computer says no...'); 
+0

La respuesta dada a esta pregunta http://stackoverflow.com/questions/791004/how-can-i-detect-if-a-delphi-class-has-a-virtual-constructor podría ayudar. – RobS

Respuesta

0

Una mirada rápida a través de la unidad de TypInfo no aparece nada útil. Creo que la noción de una "clase abstracta" es puramente en beneficio del compilador. Le da una regla que exigir - ninguna instanciación de esta clase, solo sus descendientes - pero realmente no hace nada en tiempo de ejecución, por lo que no es necesario registrar ningún RTTI para ello.

¿Por qué estás tratando de descubrir esto de todos modos, solo por curiosidad?

+0

Tengo una clase derivada de TCollection que puede contener diferentes clases de clases (TCollectionItem) con un antecesor común. Para ser específico, es una colección de columnas de cuadrícula que contiene diferentes tipos de columnas. Y ahora quiero crear un editor de colecciones designtime que permita al usuario agregar tipos de columnas registradas (usando TClassFinder) ... pero no quiero las clases de abtract en este editor. Mis clases abstractas se llaman TCustom * así que por ahora estoy filtrando usando el nombre de la clase. – mrMoo

+0

Su problema, por lo tanto, no se trata de cómo detectar clases abstractas. Su problema es cómo obtener una lista de "tipos de columna" válidos. La solución fácil es asegurarse de que solo registre las clases que son tipos de columna válidos. No registres las clases abstractas en primer lugar. La única razón para registrar una clase es para que pueda buscarla por su nombre y luego crear una instancia. No registre clases que nunca deben ser instanciadas. Debería encontrar que el VCL tampoco registra sus propias clases base "personalizadas". –

+0

Sí, muy cierto, el problema es que solo registro las clases que son "válidas", como usted sugiere, pero Delphi también registra automáticamente las clases principales, p. si registra TButton usando RegisterClass (TButton), Delphi también registrará TCustomButton, TButtonControl y así sucesivamente ...Gracias de todos modos por su publicación sobre métodos abstractos, muy interesante, pero creo que la respuesta correcta a mi pregunta es "No" – mrMoo

6

que no tienen una versión suficientemente reciente como para responder a su pregunta directamente, pero tenga en cuenta que no realmente importa si la clasees abstracta. Todo lo que hace es hacer que el compilador le impida llamar a un constructor directamente en la clase. Si coloca la referencia de clase en una variable de referencia de clase, el compilador le permitirá llamar al constructor sobre la variable, y en tiempo de ejecución tendrá una instancia de la clase supuestamente no ejecutable.

var 
    c: TClass; 
    o: TObject; 
begin 
    c := TMyAbstractClass; 
    o := c.Create; 
    Assert(o is TMyAbstractClass); 
end; 

Lo que es realmente importante es si la clase tiene ningún métodos abstractos. Puede verificarlo con bastante facilidad. Mire en el VMT de la clase. Cualquier ranura de método virtual que contiene un puntero a System._AbstractError es un método abstracto. La parte engañosa es saber cuántas ranuras de método virtual verificar, ya que eso no se graba. Allen Bauer demonstrated how to do that en una respuesta a another question, pero en los comentarios Mason Wheeler señala que puede devolver valores más grandes de lo que debería. Menciona la función GetVirtualMethodCount del JCL, que debería proporcionar un recuento más preciso de los métodos virtuales definidos por el usuario. El uso de esa función y GetVirtualMethod, también de la JCL, obtenemos esta función:

function HasAbstractMethods(c: TClass): Boolean; 
var 
    i: Integer; 
begin 
    Result := True; 
    for i := 0 to Pred(GetVirtualMethodCount(c)) do 
    if GetVirtualMethod(c, i) = @_AbstractError then 
     exit; 
    Result := False; 
end; 

Si una clase abstracta no tiene métodos abstractos, entonces, ¿cómo abstracta puede ser realmente? Debe haber sido marcado como abstracto para evitar que los desarrolladores creen instancias del mismo, pero si realmente lo desea, puede crear instancias del mismo de todos modos, por lo que marcar una clase abstracta es realmente más una advertencia que cualquier restricción real de uso.

+0

Desafortunadamente, cuando realicé algunas pruebas, el algoritmo de Allen resultó no funcionar en todos los casos. Lo investigaré un poco y publicaré una corrección en esa pregunta si puedo descifrarlo. –

+0

Aparentemente algunas otras cosas pueden ponerse allí delante del nombre. En lugar del algoritmo de Allen, pruebe con JclSysUtils.GetVirtualMethodCount, que está convenientemente ubicado en la misma unidad JCL que GetVirtualMethod. –

+0

De hecho. La versión de JCL comprueba todos los demás punteros en el VMT, y si alguno de ellos ocurre entre el primer método virtual y el nombre de clase, "acorta" la ventana de lo que considera que es el rango de métodos virtuales. –

Cuestiones relacionadas