2011-03-10 18 views
17

que tienen estas clases y un procedimiento:¿Cómo puedo determinar si un objeto Delphi es de una clase específica y no de una clase descendiente?

TParent = class(TObject); 
TChild1 = class(TParent);  
TChild2 = class(TParent); 

Procedure DoSomething(obj:TParent); 

Lo que me gustaría hacer es cuando obj es una TParent y no un descendiente lanzar una excepción.

pensé en hacer algo como esto:

if obj.classname = TParent.classname then raise exception.create.... 

pero parece un poco hacker (TM)

Más: lo que pretendía es capaz de pasar objetos que compartían propiedades/procedimientos en común. Después de pensarlo más, el objeto TParent no es realmente necesario en absoluto, lo que necesitaba era un objeto de interfaz que se muestra en mi respuesta.

+0

A partir de las respuestas ya dadas, ciertamente hay casos válidos para querer esto pero no tantos. ¿Por qué necesitas saberlo? –

+4

+1 por pensar que fue un truco. Como regla general, si estás haciendo cosas relacionadas con el tipo con * strings *, probablemente estés haciendo algo mal. –

Respuesta

0

Creo que he resuelto lo que estaba tratando de hacer, me golpeó en la cabeza anoche.

iParentInterface = interface(IUnknown); 
TChild1 = class(TInterfacedObject,iParentInterface);  
TChild2 = class(TInterfacedObject,iParentInterface); 

Procedure DoSomething(obj:iParentInterface); 
11

Está en el camino correcto, pero en lugar de comparar nombres de clase, sería más simple verificar la propiedad ClassType.

if obj.ClassType = TParent then raise exception.create.... 
+5

No solo más simple, sino también * más correcto *. Es posible que dos clases tengan el mismo nombre pero no sean de la misma clase. (La función 'ClassName' no incluye el nombre de la unidad, que de otro modo distinguiría las clases con nombre similar. No estoy seguro de qué hace con las clases anidadas.) –

+2

@Rob Hace lo obvio: 'TOuter.TInner'. –

+1

La documentación dice que se debe usar la palabra clave * is * en lugar de comparar por ClassType. – StanE

30

Es probable que encuentres los siguientes métodos TObject clase útil:

  • ClassType - devuelve la clase de un objeto
  • ClassParent - da la clase padre de la clase
  • InheritsFrom - regresa si una clase hereda de otra clase (es decir, verifica toda la cadena de herencia). Incluye la clase actual.

Por lo tanto, se puede lograr lo que quiere (desciende de TParent pero no TDescendant?) Con algo como el siguiente código (no probado, no tienen Delphi en este momento):

if obj.ClassType.InheritsFrom(TParent) 
    and not obj.ClassType.InheritsFrom(TDescendant) then... 

O , si he entendido bien y lo que desea es ver si un objeto es un TParent, y no cualquier tipo de descendiente en absoluto, tratar:

if obj.ClassType = TParent then... 

Delphi estaba muy por delante de su tiempo, proporcionando acceso a través de clases metaclasses, así que más bien th simplemente al verificar el nombre de la clase, puede acceder a un objeto de clase real.

+2

¡Adelantado a su tiempo tal vez, pero todavía muy por detrás de Smalltalk! –

+0

Sí, estuve tentado de añadir un comentario de Smalltalk en mi respuesta :) –

2

Otro enfoque: Introduzca un método abstracto en TParent, digamos CheckValidChild, y omítalo en las clases descendientes. Ahora cuando llamas al obj.CheckValidChild obtienes un EAbstractError si la instancia de obj es de la clase TParent.

11

La buena práctica en la programación orientada a objetos indica que esto no se debe hacer.Lo que usted describe es una violación directa de la Liskov substitution principle que establece que:

objetos en un programa deben ser reemplazable con las instancias de sus subtipos sin alterar el corrección de ese programa

I piense que debe explicar qué problema está tratando de resolver y luego un mejor enfoque puede ser evidente.

+0

+1 para Liskov SP. –

+2

Este fue el empujón que necesitaba, –

Cuestiones relacionadas