对一个给定的类型,想枚举类的所有属性和方法,有没有办法做到?

解决方案 »

  1.   

    引用别人的,看对你有没有帮助:问题的标题是: VCL分析(一) (100分 )
     
    来自:timerri 时间:2002-3-4 21:48:00 ID:959473 最近看到烂书充斥市场,于是很想写本书,初步的想法是想到哪里就写到哪里,最后再整理出来。于是就有了下面这些东西
    欢迎大家指正,如果有什么需要增加的部分或疑难的问题,请大家也一并提出来。从TObject谈起
    可能从我们第一次接触DELPHI的时候我们就碰到了对象和类的概念,在后来的学习过程中又不可避免的继续与类和对象打着
    交道。我们现在就从所有VCL类的基类Tobject谈起。
    Tobject究竟实现了什么?他凭什么做所有类的基类?看来只有看代码才能解决问题。来,让我们转到system.pas来看一看。
      TObject = class
        constructor Create;//构造函数,空的
        procedure Free;//析构函数,也是空的
        class function InitInstance(Instance: Pointer): TObject;//初始化实例,并装载接口
        procedure CleanupInstance;//清空实例
        function ClassType: TClass;//类类型
        class function ClassName: ShortString;//类名
        class function ClassNameIs(const Name: string): Boolean;//类名是否是name
        class function ClassParent: TClass;//父类
        class function ClassInfo: Pointer;//类信息
        class function InstanceSize: Longint;//实例大小
        class function InheritsFrom(AClass: TClass): Boolean;//是否从aclass继承
        class function MethodAddress(const Name: ShortString): Pointer;//按名称找方法地址
        class function MethodName(Address: Pointer): ShortString;//按地址找方法名
        function FieldAddress(const Name: ShortString): Pointer;
        function GetInterface(const IID: TGUID; out Obj): Boolean;
        class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
        class function GetInterfaceTable: PInterfaceTable;
        function SafeCallException(ExceptObject: TObject;
          ExceptAddr: Pointer): HResult; virtual;
        procedure AfterConstruction; virtual;
        procedure BeforeDestruction; virtual;
        procedure Dispatch(var Message); virtual;
        procedure DefaultHandler(var Message); virtual;
        class function NewInstance: TObject; virtual;
        procedure FreeInstance; virtual;
        destructor Destroy; virtual;
      end;
    以上是Tobject的声明。我们先大致看看能得到什么!Create, Free,Destroy我们就不去说它了,构造函数和析构函数的概
    念好像每本面向对象的书里都有。
    可是ClassType ClassName ClassNameIs ClassParent ClassInfo InheritsFrom InstanceSize,这些东西是干什么的?听过
    RTTI(执行期类型识别)的朋友可能会有点想法了。对,利用他们就可以得到RTTI的一些信息,Tobject作为所有类的基类,把
    这种得到RTTI信息的能力带给了所有的类。没听过RTTI的朋友可能现在就有点昏,没关系,我们现在就来讲一下。在DELPHI中
    ,每个类都有一个VMT(虚拟方法表),每个对象的起始四个字节就保存着对应VMT的32位指针。下面是HELP里抄的一段,好好看
    看VMT里到底有些什么。
    Offset Type Description
    -76 Pointer pointer to virtual method table (or nil)
    -72 Pointer pointer to interface table (or nil)
    -68 Pointer pointer to Automation information table (or nil)
    -64 Pointer pointer to instance initialization table (or nil)
    -60 Pointer pointer to type information table (or nil)
    -56 Pointer pointer to field definition table (or nil)
    -52 Pointer pointer to method definition table (or nil)
    -48 Pointer pointer to dynamic method table (or nil)
    -44 Pointer pointer to short string containing class name
    -40 Cardinal instance size in bytes
    -36 Pointer pointer to a pointer to ancestor class (or nil)
    -32 Pointer pointer to entry point of SafecallException method (or nil)
    -28 Pointer entry point of AfterConstruction method
    -24 Pointer entry point of BeforeDestruction method
    -20 Pointer entry point of Dispatch method
    -16 Pointer entry point of DefaultHandler method
    -12 Pointer entry point of NewInstance method
    -8 Pointer entry point of FreeInstance method
    -4 Pointer entry point of Destroy destructor
    0 Pointer entry point of first user-defined virtual method
    4 Pointer entry point of second user-defined virtual method
    真是一堆好东西。类的主要信息就包含在这里了,它才是真正RTTI的主角,ClassType ClassName ClassNameIs 
    ClassParent ClassInfo InheritsFrom InstanceSize这堆函数不过是从VMT中读取出对应的参数罢了。
    你不会要问我RTTI有什么用吧!我昏!试想一下,一个函数传了个对象给你,你又不能确定它究竟是个什么
    对象,就如VCL中大量存在的(Sender: Tobject),那么用sender.ClassName就没错了,看看是否知道了传过
    来的是什么东西?
    CleanupInstance FreeInstance InitInstance NewInstance,这些东西又是干什么的?看名字大概就能看出
    来,这是对象创建和释放时的操作。所有的构造函数(就是以constructor打头的)都自动的运行Newinstance,
    Newinstance为对象实例分配内存并返回对象指针。在Newinstance中调用了InitInstance来进行对象的初始化操作。
    在InitInstance中清零了对象实例并且赋值了接口地址。CleanupInstance FreeInstance就是负责对象实例的释放。
    请注意,如果需要创建一个非默认内存大小的对象的话,可以重载NewInstance,但是同时也必须重载FreeInstance
    来释放内存,重载的NewInstance也必须调用InitInstance而不是用inherited。
    还剩下几个函数我这里就不一一讲解了,大家可以自己看看源代码。再来谈谈面向对象
    做DELPHI程序,我们大部分时间都在和对象打交道,但是我们是否真的明白了面向对象的所有?恐怕不见得
    ,做个简单的测试,Tclass=class of Tobject; 这里Tclass是个什么东西?如果你说不清楚,那么就老老实实往下看。
    面向对象是通过为数据和代码建立分块的内存区域来提供对程序模块化的程序设计方法。与C++有些不同,
    DELPHI中的对象包含数据(fields)、方法(methods)和属性(properties),而C++中只包含数据(比较奇怪,c++中叫property)
    和方法,DELPHI中的属性更有利于面向对象的代码封装,而且更适于可视化编程。属性其实是一个对外接口,一般和一个数据相关联,
    他决定了这个数据怎样被读和怎样被修改。
        DELPHI中对象的封装也是靠“类”实现的。类其实是对象的抽象、也是对象的模板,对象是类的实例。在DELPHI中,
    每个对象都有一份自己数据部分的内存拷贝,但是同类的对象共用相同的代码部分。对象的创建由类来负责,也就是
    constructor声明的方法来创建。对象在实现上其实是个指针,他指向自己的实体部分,但我们用他的时候不用把它当作指针,
    当我们使用了^时他才确实当作指针使用。现在来看看我们的问题,什么是Tclass?千万不要被前面那个T迷惑了让你认为它是一个类,
    其实它是一个类型,单独看Tclass看不出什么来,当我们用它来声明变量后你就会看出他的作用来,那么我们就声明aobj:Tclass看看
    有什么效果。这时候,就可以把任何类赋值给aobj,如aobj:=button1.classtype;这样aobj的值就是Tbutton。如果再要创建这样的对象,
    就用aobj.create就可以得到另一个Tbutton的实例。而且aobj还可以当作参数传递,这样我们需要动态创建对象而又不能确定对象类型的
    时候,就不至于那么一筹莫展了。 
      

  2.   

    同时你再看看typinfo单元;来自:delphfan 时间:2001-9-7 15:53:00 ID:615474 下面为一过程,对的属性全放在AStrings中
    procedure GetClassProperties(AClass: TObject; AStrings: TStrings);
    { This method retrieves the property names and types for the given object
      and adds that information to the AStrings parameter. }
    var
      PropList: PPropList;
      ClassTypeInfo: PTypeInfo;
      ClassTypeData: PTypeData;
      i: integer;
      NumProps: Integer;
    begin
      ClassTypeInfo := aClass.ClassType.ClassInfo ;
      ClassTypeData := GetTypeData(ClassTypeInfo);
      if ClassTypeData.PropCount <> 0 then
      begin
        GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
        try
          GetPropInfos(AClass.ClassInfo, PropList);
          for i := 0 to ClassTypeData.PropCount - 1 do
            if not (PropList[i]^.PropType^.Kind = tkMethod) then
              AStrings.Add(Format('%s: %s', [PropList[i]^.Name, PropList[i]^.PropType^.Name]));
          NumProps := GetPropList(AClass.ClassInfo, [tkMethod], PropList);
          if NumProps <> 0 then begin
            AStrings.Add('');
            AStrings.Add('   EVENTS   ================ ');
            AStrings.Add('');
          end;
          // Fill the AStrings with the events.
          for i := 0 to NumProps - 1 do
              AStrings.Add(Format('%s: %s', [PropList[i]^.Name, PropList[i]^.PropType^.Name]));    finally
          FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
        end;
      end;
    end;
    之前uses单元TypInfo,简单吧