delphi RTTI机制学习(一)

RTTI即运行时类型识别,用来识别动态对象的类型。即使我们仅仅有基类的指针和引用,可以识别出该指针和引用所指向那个类(基类或派生类)。RTTI会带来一定的性能开销。

一、新建一个Console工程

二、定义一个类并引用System.Rtti (我用的是XE3,2010-XE的直接用Rtti)写好后按Ctrl+Shit+G生成方法

 

三、测试一下 获取类属性(property)

 

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Rtti;

type
  TMyClass = class
    private
      FID: Integer;
      FName: String;
    protected
      procedure WriteName();
      function GetName():String;
    published
      property TestProp1:Integer read FID write FID;
      property TestProp2:String read FName write FName;
      property TestProp3:String read FName write FName;
      property TestProp4:Integer read FID write FID;

  end;

{ TMyClass }

function TMyClass.GetName: String;
begin

end;

procedure TMyClass.WriteName;
begin

end;

var
 ctx: TRttiContext;
 t: TRttiType;
 prop: TRttiProperty;

begin
 ctx := TRttiContext.Create;
 t := ctx.GetType(TMyClass);
 for prop in t.GetProperties do
 begin
   //获取属性类型
   WriteLn(prop.PropertyType.ToString());
 end;
 ctx.Free;
 ReadLn;

end.

 

如图,获取了Property的四个字段属性

 

四、测试二获取类成员(private)

var
 ctx: TRttiContext;
 t: TRttiType;
 prop: TRttiProperty;
 m: TRttiMethod;
 field: TRttiField;

begin
 ctx := TRttiContext.Create;
 t := ctx.GetType(TMyClass);
 for field in t.GetFields do
 begin
    //获取成员
   WriteLn(field.ToString());
 end;
 ctx.Free;
 ReadLn;

end.

(04 08代表地址偏移)?

 

还有更多的属性GetMethds获取方法的 自行试验吧

 

五、动态调用方法

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Rtti, System.TypInfo;

type
  TMyClass = class
    private
      FID: Integer;
      FName: String;
    public
      procedure WriteName(); overload;
      procedure AddName(const param1: String);overload;
      function GetName():String;

    published
      property TestProp1:Integer read FID write FID;
      property TestProp2:String read FName write FName;
      property TestProp3:String read FName write FName;
      property TestProp4:Integer read FID write FID;
  end;

{ TMyClass }

function TMyClass.GetName: String;
begin
  WriteLn('调用了GetName过程');
  Result := '调用成功';
end;

procedure TMyClass.AddName(const param1: String);
begin
   WriteLn('调用了带有参数的AddName方法:' + param1);
end;
procedure TMyClass.WriteName;
begin
    WriteLn('调用了WriteName方法');
end;




var
 ctx: TRttiContext;
 t: TRttiType;
 prop: TRttiProperty;
 m: TRttiMethod;
 field: TRttiField;
 r: TValue;
 cls: TMyClass;


begin
 ctx := TRttiContext.Create;
 cls := TMyClass.Create;
 try
    t := ctx.GetType(TMyClass);
    //通过传入方法名获取方法地址 只能取public方法 protected的取不到
    m := t.GetMethod('WriteName');
    m.Invoke(cls, []);

    //如果是重载方法报参数不匹配
    m := t.GetMethod('AddName');
    m.Invoke(cls, ['有参数的']);
    //调用带有返回值的
    m := t.GetMethod('GetName');

    r := m.Invoke(cls,[]);

    case r.Kind of
      tkString:
        WriteLn('返回值类型:String');
      tkUString:
        WriteLn('返回值类型:Unicode String');
    end;
    WriteLn('返回值:' + r.ToString());


 finally
    cls.Free;
    ctx.Free;
 end;

 ReadLn;

end.

 

 

posted @ 2013-04-23 09:10  TryHard  阅读(1438)  评论(0编辑  收藏  举报