日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

DELPHI RTTI淺析

 Jason(徐子) 2010-09-06

目錄
===============================================================================
⊙ RTTI 簡介
⊙ 類(class) 和 VMT 的關系
⊙ 類(class)、類的類(class of class)、類變量(class variable) 的關系
⊙ TObject.ClassType 和 TObject.ClassInfo
⊙ is 和 as 運算符的原理
⊙ TTypeInfo – RTTI 信息的結(jié)構
⊙ 獲取類(class)的屬性(property)信息
⊙ 獲取方法(method)的類型信息
⊙ 獲取有序類型(ordinal)、集合(set)類型的 RTTI 信息
⊙ 獲取其它數(shù)據(jù)類型的 RTTI 信息
===============================================================================

本文排版格式為:
    正文由窗口自動換行;所有代碼以 80 字符為邊界;中英文字符以空格符分隔。

(作者保留對本文的所有權利,未經(jīng)作者同意請勿在在任何公共媒體轉(zhuǎn)載。)


正文
===============================================================================
⊙ RTTI 簡介
===============================================================================

RTTI(Run-Time Type Information) 翻譯過來的名稱是“運行期類型信息”,也就是說可以在運行期獲得數(shù)據(jù)類型或類(class)的信息。這個 RTTI 到底有什么用處,我現(xiàn)在也說不清楚。我是在閱讀 Delphi 持續(xù)機制的代碼中發(fā)現(xiàn)了很多 RTTI 的運用,只好先把 RTTI 學習一遍。下面是我的學習筆記。如果你發(fā)現(xiàn)了錯誤請告訴我。謝謝!

Delphi 的 RTTI 主要分為類(class)的 RTTI 和一般數(shù)據(jù)類型的 RTTI,下面從類(class)開始。

===============================================================================
⊙ 類(class) 和 VMT 的關系
===============================================================================

一個類(class),從編譯器的角度來看就是一個指向 VMT 的指針(在后文用 VMTptr 表示)。在類的 VMTptr 的負地址方向存儲了一些類信息的指針,這些指針的值和指針所指的內(nèi)容在編譯后就確定了。比如 VMTptr - 44 的內(nèi)容是指向類名稱(ClassName)的指針。不過一般不使用數(shù)值來訪問這些類信息,而是通過 System.pas 中定義的以 vmt 開頭的常量,如 vtmClassName、vmtParent 等來訪問。

類的方法有兩種:對象級別的方法和類級別的方法。兩者的 Self 指針意義是不同的。在對象級別的方法中 Self 指向?qū)ο蟮刂房臻g,因此可以用它來訪問對象的成員函數(shù);在類級別的方法中 Self 指向類的 VMT,因此只能用它來訪問 VMT 信息,而不能訪問對象的成員字段。

===============================================================================
⊙ 類(class)、類的類(class of class)、類變量(class variable) 的關系
===============================================================================

上面說到類(class) 就是 VMTptr。在 Delphi 中還可以用 class of 關鍵字定義類的類,并且可以使用類的類定義類變量。從語法上理解這三者的關鍵并不難,把類當成普通的數(shù)據(jù)類型來考慮就可以了。在編譯器級別上表現(xiàn)如何呢?

為了簡化討論,我們使用 TObject、TClass 和 TMyClass 來代表上面說的三種類型:

type
  TClass = class of TObject;
var
  TMyClass: TClass;
  MyObject: TObject;
begin
  TMyClass := TObject;
  MyObject := TObject.Create;
  MyObject := TClass.Create;
  MyObject := TMyClass.Create;
end;
 
在上面的例子中,三個 TObject 對象都被成功地創(chuàng)建了。編譯器的實現(xiàn)是:TObject 是一個 VMTPtr 常量。TClass 也是一個 VMTptr 常量,它的值就是 TObject。TMyClass 是一個 VMTptr 變量,它被賦值為 TObject。TObject.Create 與 TClass.Create 的匯編代碼完全相同。但 TClass 不僅缺省代表一個類,而且還(主要)代表了類的類型,可以用它來定義類變量,實現(xiàn)一些類級別的操作。

===============================================================================
⊙ TObject.ClassType 和 TObject.ClassInfo
===============================================================================

function TObject.ClassType: TClass;
begin
  Pointer(Result) := PPointer(Self)^;
end;

TObject.ClassType 是對象級別的方法,Self 的值是指向?qū)ο髢?nèi)存空間的指針,對象內(nèi)存空間的前 4 個字節(jié)是類的 VMTptr。因此這個函數(shù)的返回值就是類的 VMTptr。

class function TObject.ClassInfo: Pointer;
begin
  Result := PPointer(Integer(Self) + vmtTypeInfo)^;
end;

TObject.ClassInfo 使用 class 關鍵字定義,因此是一個類級別的方法。該方法中的 Self 指針就是 VMTptr。所以這個函數(shù)的返回值是 VMTptr 負方向的 vmtTypeInfo 的內(nèi)容。

TObject.ClassInfo 返回的 Pointer 指針,實際上是指向類的 RTTI 結(jié)構的指針。但是不能訪問 TObject.ClassInfo 指向的內(nèi)容(TObject.ClassInfo 返回值是 0),因為 Delphi 只在 TPersistent 類及 TPersistent 的后繼類中產(chǎn)生 RTTI 信息。(從編譯器的角度來看,這是在 TPersistent 類的聲明之前使用 {$M+} 指示字的結(jié)果。)

TObject 還定義了一些獲取類 RTTI 信息的函數(shù),列舉在下,就不一一分析了:

  TObject.ClassName: ShortString;   類的名稱
  TObject.ClassParent: TClass;      對象的父類
  TObject.InheritsFrom: Boolean;    是否繼承自某類
  TObject.InstanceSize: Longint;    對象實例的大小

===============================================================================
⊙ is 和 as 運算符的原理
===============================================================================

我們知道可以在運行期使用 is 關鍵字判斷一個對象是否屬于某個類,可以使用 as 關鍵字把某個對象安全地轉(zhuǎn)換為某個類。在編譯器的層次上,is 和 as 的操作是由 System.pas 中兩個函數(shù)完成的。

{ System.pas }
function _IsClass(Child: TObject; Parent: TClass): Boolean;
begin
  Result := (Child <> nil) and Child.InheritsFrom(Parent);
end;

_IsClass 很簡單,它使用 TObject 的 InheritsForm 函數(shù)判斷該對象是否是從某個類或它的父類中繼承下來的。每個類的 VMT 中都有一項 vmtParent 指針,指向該類的父類的 VMT。TObject.InheritsFrom 實際上是通過[遞歸]判斷父類 VMT 指針是否等于自己的 VMT 指針來判斷是否是從該類繼承的。

{ System.pas }
class function TObject.InheritsFrom(AClass: TClass): Boolean;
var
  ClassPtr: TClass;
begin
  ClassPtr := Self;
  while (ClassPtr <> nil) and (ClassPtr <> AClass) do
    ClassPtr := PPointer(Integer(ClassPtr) + vmtParent)^;
  Result := ClassPtr = AClass;
end;

as 操作符實際上是由 System.pas 中的 _AsClass 函數(shù)完成的。它簡單地調(diào)用 is 操作符判斷對象是否屬于某個類,如果不是就觸發(fā)異常。雖然 _AsClass 返回值為 TObject 類型,但編譯器會自動把返回的對象改變?yōu)?Parent 類,否則返回的對象沒有辦法使用 TObject 之外的方法和數(shù)據(jù)。

{ System.pas }
function _AsClass(Child: TObject; Parent: TClass): TObject;
begin
  Result := Child;
  if not (Child is Parent) then
    Error(reInvalidCast);   // loses return address
end;

===============================================================================
⊙ TTypeInfo – RTTI 信息的結(jié)構
===============================================================================

RTTI 信息的結(jié)構定義在 TypInfo.pas 中:

  TTypeInfo = record        // TTypeInfo 是 RTTI 信息的結(jié)構
    Kind: TTypeKind;        // RTTI 信息的數(shù)據(jù)類型
    Name: ShortString;      // 數(shù)據(jù)類型的名稱
   {TypeData: TTypeData}    // RTTI 的內(nèi)容
  end;

TTypeInfo 就是 RTTI 信息的結(jié)構。TObject.ClassInfo 返回指向存放 class TTypeInfo 信息的指針。Kind 是枚舉類型,它表示 RTTI 結(jié)構中所包含數(shù)據(jù)類型。Name 是數(shù)據(jù)類型的名稱。注意,最后一個字段 TypeData 被注釋掉了,這說明該處的結(jié)構內(nèi)容根據(jù)不同的數(shù)據(jù)類型有所不同。

TTypeKind 枚舉定義了可以使用 RTTI 信息的數(shù)據(jù)類型,它幾乎包含了所有的 Delphi 數(shù)據(jù)類型,其中包括 tkClass。

  TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
    tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
    tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray);

TTypeData 是個巨大的記錄類型,在此不再列出,后文會根據(jù)需要列出該記錄的內(nèi)容。

===============================================================================
⊙ 獲取類(class)的屬性(property)信息
===============================================================================

這一段是 RTTI 中最復雜的部分,努力把本段吃透,后面的內(nèi)容都是非常簡單的。

下面是一個獲取類的屬性的例子:

procedure GetClassProperties(AClass: TClass; AStrings: TStrings);
var
  PropCount, I: SmallInt;
  PropList: PPropList;
  PropStr: string;
begin
  PropCount := GetTypeData(AClass.ClassInfo).PropCount;
  GetPropList(AClass.ClassInfo, PropList);
  for I := 0 to PropCount - 1 do
  begin
    case PropList[I]^.PropType^.Kind of
      tkClass      : PropStr := '[Class] ';
      tkMethod     : PropStr := '[Method]';
      tkSet        : PropStr := '[Set]   ';
      tkEnumeration: PropStr := '[Enum]  ';
    else
      PropStr := '[Field] ';
    end;
    PropStr := PropStr + PropList[I]^.Name;
    PropStr := PropStr + ': ' + PropList[I]^.PropType^.Name;
    AStrings.Add(PropStr);
  end;
  FreeMem(PropList);
end;

你可以在表單上放置一個 TListBox ,然后執(zhí)行以下語句觀察執(zhí)行結(jié)果:

  GetClassProperties(TForm1, ListBox1.Items);

該函數(shù)先使用 GetTypeData 函數(shù)獲得類的屬性數(shù)量。GetTypeData 是 TypInfo.pas 中的一個函數(shù),它的功能是返回 TTypeInfo 的 TypeData 數(shù)據(jù)的指針:

{ TypInfo.pas }
function GetTypeData(TypeInfo: PTypeInfo): PTypeData; assembler;

class 的 TTypeData 結(jié)構如下:

  TTypeData = packed record
    case TTypeKind of
      tkClass: (
        ClassType: TClass;         // 類 (VMTptr)
        ParentInfo: PPTypeInfo;    // 父類的 RTTI 指針
        PropCount: SmallInt;       // 屬性數(shù)量
        UnitName: ShortStringBase; // 單元的名稱
       {PropData: TPropData});     // 屬性的詳細信息
  end;

其中的 PropData 又是一個大小可變的字段。TPropData 的定義如下:

  TPropData = packed record
    PropCount: Word;       // 屬性數(shù)量
    PropList: record end;  // 占位符,真正的意義在下一行
    {PropList: array[1..PropCount] of TPropInfo}
  end;

每個屬性信息在內(nèi)存中的結(jié)構就是 TPropInfo,它的定義如下:

  PPropInfo = ^TPropInfo;
  TPropInfo = packed record
    PropType: PPTypeInfo;    // 屬性類型信息指針的指針
    GetProc: Pointer;        // 屬性的 Get 方法指針
    SetProc: Pointer;        // 屬性的 Set 方法指針
    StoredProc: Pointer;     // 屬性的 StoredProc 指針
    Index: Integer;          // 屬性的 Index 值
    Default: Longint;        // 屬性的 Default 值
    NameIndex: SmallInt;     // 屬性的名稱索引(以 0 開始計數(shù))
    Name: ShortString;       // 屬性的名稱
  end;

為了方便訪問屬性信息,TypInfo.pas 中還定義了指向 TPropInfo 數(shù)組的指針:

  PPropList = ^TPropList;
  TPropList = array[0..16379] of PPropInfo;

我們可以使用 GetPropList 獲得所有屬性信息的指針數(shù)組,數(shù)組用完以后要記得用 FreeMem 把數(shù)組的內(nèi)存清除。

{ TypInfo.pas }
function GetPropList(TypeInfo: PTypeInfo; out PropList: PPropList): Integer;

GetPropList 傳入類的 TTypeInfo 指針和 TPropList 的指針,它為 PropList 分配一塊內(nèi)存后把該內(nèi)存填充為指向 TPropInfo 的指針數(shù)組,最后返回屬性的數(shù)量。

上面的例子演示了如何獲得類的所有屬性信息,也可以根據(jù)屬性的名稱單獨獲得屬性信息:

{ TypInfo.pas }
function GetPropInfo(TypeInfo: PTypeInfo; const PropName: string): PPropInfo;

GetPropInfo 根據(jù)類的 RTTI 指針和屬性的名稱字符串,返回屬性的信息 TPropInfo 的指針。如果沒有找到該屬性,則返回 nil。GetPropInfo 很容易使用,舉個例子:

  ShowMessage(GetPropInfo(TForm, 'Name')^.PropType^.Name);

這句調(diào)用顯示了 TForm 類的 Name 屬性的類型名稱:TComponentName。

===============================================================================
⊙ 獲取方法(method)的類型信息
===============================================================================

所謂方法就是以 of object 關鍵字聲明的函數(shù)指針,下面的函數(shù)可以顯示一個方法的類型信息:

procedure GetMethodTypeInfo(ATypeInfo: PTypeInfo; AStrings: TStrings);
type
  PParamData = ^TParamData;
  TParamData = record       // 函數(shù)參數(shù)的數(shù)據(jù)結(jié)構
    Flags: TParamFlags;     // 參數(shù)傳遞規(guī)則
    ParamName: ShortString; // 參數(shù)的名稱
    TypeName: ShortString;  // 參數(shù)的類型名稱
  end;
  function GetParamFlagsName(AParamFlags: TParamFlags): string;
  var
    I: Integer;
  begin
    Result := '';
    for I := Integer(pfVar) to Integer(pfOut) do begin
      if I = Integer(pfAddress) then Continue;
      if TParamFlag(I) in AParamFlags then
        Result := Result + ' ' + GetEnumName(TypeInfo(TParamFlag), I);
    end;
  end;
var
  MethodTypeData: PTypeData;
  ParamData: PParamData;
  TypeStr: PShortString;
  I: Integer;
begin
  MethodTypeData := GetTypeData(ATypeInfo);
  AStrings.Add('---------------------------------');
  AStrings.Add('Method Name: ' + ATypeInfo^.Name);
  AStrings.Add('Method Kind: ' + GetEnumName(TypeInfo(TMethodKind),
    Integer(MethodTypeData^.MethodKind)));
  AStrings.Add('Params Count: '+ IntToStr(MethodTypeData^.ParamCount));
  AStrings.Add('Params List:');
  ParamData := PParamData(@MethodTypeData^.ParamList);
  for I := 1 to MethodTypeData^.ParamCount do
  begin
    TypeStr := Pointer(Integer(@ParamData^.ParamName) +
      Length(ParamData^.ParamName) + 1);
    AStrings.Add(Format('  [%s] %s: %s',[GetParamFlagsName(ParamData^.Flags),
      ParamData^.ParamName, TypeStr^]));
    ParamData := PParamData(Integer(ParamData) + SizeOf(TParamFlags) +
      Length(ParamData^.ParamName) + Length(TypeStr^) + 2);
  end;
  if MethodTypeData^.MethodKind = mkFunction then
    AStrings.Add('Result Value: ' + PShortString(ParamData)^);
end;

作為實驗,在表單上放置一個 TListBox,然后執(zhí)行以下代碼,觀察執(zhí)行結(jié)果:

type
  TMyMethod = function(A: array of Char; var B: TObject): Integer of object;
procedure TForm1.FormCreate(Sender: TObject);
begin
  GetMethodTypeInfo(TypeInfo(TMyMethod), ListBox1.Items);
  GetMethodTypeInfo(TypeInfo(TMouseEvent), ListBox1.Items);
  GetMethodTypeInfo(TypeInfo(TKeyPressEvent), ListBox1.Items);
  GetMethodTypeInfo(TypeInfo(TMouseWheelEvent), ListBox1.Items);
end;

由于獲取方法的類型信息比較復雜,我盡量壓縮代碼也還是有這么長,讓我們看看它的實現(xiàn)原理。GetMethodTypeInfo 的第一個參數(shù)是 PTypeInfo 類型,表示方法的類型信息地址。第二個參數(shù)是一個字符串列表,可以使用任何實現(xiàn) TStrings 操作的對象。我們可以使用 System.pas 中的 TypeInfo 函數(shù)獲得任何類型的 RTTI 信息指針。TypeInfo 函數(shù)像 SizeOf 一樣,是內(nèi)置于編譯器中的。

GetMethodTypeInfo 還用到了 TypInfo.pas 中的 GetEnumName 函數(shù)。這個函數(shù)通過枚舉類型的整數(shù)值得到枚舉類型的名稱。

function GetEnumName(TypeInfo: PTypeInfo; Value: Integer): string;

與獲取類(class)的屬性信息類似,方法的類型信息也在 TTypeData 結(jié)構中

  TTypeData = packed record
    case TTypeKind of
      tkMethod: (
        MethodKind: TMethodKind;            // 方法指針的類型
        ParamCount: Byte;                   // 參數(shù)數(shù)量
        ParamList: array[0..1023] of Char   // 參數(shù)詳細信息,見下行注釋
       {ParamList: array[1..ParamCount] of
          record
            Flags: TParamFlags;             // 參數(shù)傳遞規(guī)則
            ParamName: ShortString;         // 參數(shù)的名稱
            TypeName: ShortString;          // 參數(shù)的類型
          end;
        ResultType: ShortString});          // 返回值的名稱
  end;

TMethodKind 是方法的類型,定義如下:

  TMethodKind = (mkProcedure, mkFunction, mkConstructor, mkDestructor,
    mkClassProcedure, mkClassFunction,
    { Obsolete }
    mkSafeProcedure, mkSafeFunction);

TParamsFlags 是參數(shù)傳遞的規(guī)則,定義如下:

  TParamFlag = (pfVar, pfConst, pfArray, pfAddress, pfReference, pfOut);
  TParamFlags = set of TParamFlag;

由于 ParamName 和 TypeName 是變長字符串,不能直接取用該字段的值,而應該使用指針步進的方法,取出參數(shù)信息,所以上面的代碼顯得比較長。

===============================================================================
⊙ 獲取有序類型(ordinal)、集合(set)類型的 RTTI 信息
===============================================================================

討論完了屬性和方法的 RTTI 信息之后再來看其它數(shù)據(jù)類型的 RTTI 就簡單多了。所有獲取 RTTI 的原理都是通過 GetTypeData 函數(shù)得到 TTypeData 的指針,再通過 TTypeInfo.TypeKind 來解析 TTypeData。任何數(shù)據(jù)類型的 TTypeInfo 指針可以通過 TypeInfo 函數(shù)獲得。

有序類型的 TTypeData 定義如下:

TTypeData = packed record
  tkInteger, tkChar, tkEnumeration, tkSet, tkWChar: (
    OrdType: TOrdType;         // 有序數(shù)值類型
    case TTypeKind of
      case TTypeKind of
        tkInteger, tkChar, tkEnumeration, tkWChar: (
          MinValue: Longint;   // 類型的最小值
          MaxValue: Longint;   // 類型的最大值
          case TTypeKind of
            tkInteger, tkChar, tkWChar: ();
            tkEnumeration: (
              BaseType: PPTypeInfo;      // 指針的指針,它指向枚舉的 PTypeInfo
              NameList: ShortStringBase;     // 枚舉的名稱字符串(不能直接取用)
              EnumUnitName: ShortStringBase)); // 所在的單元名稱(不能直接取用)
          tkSet: (
            CompType: PPTypeInfo));            // 指向集合基類 RTTI 指針的指針
end;

下面是一個獲取有序類型和集合類型的 RTTI 信息的函數(shù):

procedure GetOrdTypeInfo(ATypeInfo: PTypeInfo; AStrings: TStrings);
var
  OrdTypeData: PTypeData;
  I: Integer;
begin
  OrdTypeData := GetTypeData(ATypeInfo);
  AStrings.Add('------------------------------------');
  AStrings.Add('Type Name: ' + ATypeInfo^.Name);
  AStrings.Add('Type Kind: ' + GetEnumName(TypeInfo(TTypeKind),
    Integer(ATypeInfo^.Kind)));
  AStrings.Add('Data Type: ' + GetEnumName(TypeInfo(TOrdType),
    Integer(OrdTypeData^.OrdType)));
  if ATypeInfo^.Kind <> tkSet then begin
    AStrings.Add('Min Value: ' + IntToStr(OrdTypeData^.MinValue));
    AStrings.Add('Max Value: ' + IntToStr(OrdTypeData^.MaxValue));
  end;
  if ATypeInfo^.Kind = tkSet then
    GetOrdTypeInfo(OrdTypeData^.CompType^, AStrings);
  if ATypeInfo^.Kind = tkEnumeration then
    for I := OrdTypeData^.MinValue to OrdTypeData^.MaxValue do
      AStrings.Add(Format('  Value %d: %s', [I, GetEnumName(ATypeInfo, I)]));
end;

在表單上放置一個 TListBox,運行以下代碼查看結(jié)果:

type TMyEnum = (EnumA, EnumB, EnumC);
procedure TForm1.FormCreate(Sender: TObject);
begin
  GetOrdTypeInfo(TypeInfo(Char), ListBox1.Items);
  GetOrdTypeInfo(TypeInfo(Integer), ListBox1.Items);
  GetOrdTypeInfo(TypeInfo(TFormBorderStyle), ListBox1.Items);
  GetOrdTypeInfo(TypeInfo(TBorderIcons), ListBox1.Items);
  GetOrdTypeInfo(TypeInfo(TMyEnum), ListBox1.Items);
end;

(如果枚舉元素沒有按缺省的 0 基準定義,那么將不能產(chǎn)生 RTTI 信息,為什么?)

===============================================================================
⊙ 獲取其它數(shù)據(jù)類型的 RTTI 信息
===============================================================================

上面討論了幾個典型的 RTTI 信息的運行,其它的數(shù)據(jù)類型的 RTTI 信息的獲取方法與上面類似。由于這些操作更加簡單,就不一一討論。下面概述其它類型的 RTTI 信息的情況:

LongString、WideString 和 Variant 沒有 RTTI 信息;
ShortString 只有 MaxLength 信息;
浮點數(shù)類型只有 FloatType: TFloatType 信息;
  TFloatType = (ftSingle, ftDouble, ftExtended, ftComp, ftCurr);
Int64 只有最大值和最小值信息(也是 64 位整數(shù)表示);
Interface 和動態(tài)數(shù)組不太熟悉,就不作介紹了。

===============================================================================
⊙ 結(jié)束
===============================================================================
 

2007-3-31 0:28:40   

 2007-3-31 0:29:46   


本文上篇基本上是 RTTI 入門介紹,續(xù)篇介紹了所有 TypInfo.pas 中的函數(shù),附加了 Classes.pas、Graphics.pas、Controls.pas 中的幾個 RTTI 相關函數(shù)。對于關鍵函數(shù)的代碼提供匯編注釋。希望本文覆蓋了 Delphi 中 80% 的 RTTI 函數(shù)。時間倉促,錯誤難免,敬請批評指正。


本文排版格式為:
    正文由窗口自動換行;所有代碼以 80 字符為邊界;中英文字符以空格符分隔。

(作者保留對本文的所有權利,未經(jīng)作者同意請勿在在任何公共媒體轉(zhuǎn)載。)


目 錄
===============================================================================
⊙ GetTypeData 函數(shù)
⊙ GetPropInfo 函數(shù)
⊙ FindPropInfo 函數(shù)
⊙ GetPropInfos 函數(shù)
⊙ SortPropList 函數(shù)
⊙ GetPropList 函數(shù)
------------------------------------------------------
⊙ GetObjectPropClass 函數(shù)
⊙ PropType / PropIsType 函數(shù)
⊙ IsPublishedProp 函數(shù)
⊙ IsStoredProp 函數(shù)
⊙ FreeAndNilProperties 函數(shù)
⊙ SetToString / StringToSet 函數(shù)
⊙ GetEnumName / GetEnumValue / GetEnumNameValue 函數(shù)
------------------------------------------------------
⊙ GetOrdProp 函數(shù)詳解
⊙ SetOrdProp 函數(shù)
⊙ GetEnumProp / SetEnumProp 函數(shù)
⊙ GetSetProp / SetSetProp 函數(shù)
⊙ GetObjectProp / SetObjectProp 函數(shù)
⊙ GetStrProp / SetStrProp 函數(shù)
⊙ GetFloatProp / SetFloatProp 函數(shù)
⊙ GetPropValue / SetPropValue 函數(shù)
⊙ TPublishableVariantType class
------------------------------------------------------
⊙ RegisterClass / FindClass 系列函數(shù) (Classes.pas)
⊙ IdentToInt / IntToIdent 系列函數(shù) (Classes.pas)
===============================================================================


正 文
===============================================================================
⊙ GetTypeData 函數(shù)
===============================================================================
GetTypeData 函數(shù)根據(jù) TTypeInfo 指針獲得 TTypeData 的地址。

function GetTypeData(TypeInfo: PTypeInfo): PTypeData;
asm
        XOR     EDX,EDX                           ; EDX 清零
        MOV     DL,[EAX].TTypeInfo.Name.Byte[0]   ; 獲得 Name 字符串長度
        LEA     EAX,[EAX].TTypeInfo.Name[EDX+1]   ; 獲得 TTypeData 的地址
end;

===============================================================================
⊙ GetPropInfo 函數(shù)
===============================================================================
GetPropInfo 函數(shù)用于獲得屬性的 RTTI 指針 PPropInfo。它有四種重載形式,后面三種重載的實現(xiàn)都是調(diào)用第一種形式。AKinds 參數(shù)用于限制屬性的類型,如果得到的 PPropInfo 不屬于指定的類型,則返回 nil。

  function GetPropInfo(TypeInfo: PTypeInfo; const PropName: string): PPropInfo;

  function GetPropInfo(Instance: TObject; const PropName: string;
    AKinds: TTypeKinds = []): PPropInfo;
  function GetPropInfo(AClass: TClass; const PropName: string;
    AKinds: TTypeKinds = []): PPropInfo;
  function GetPropInfo(TypeInfo: PTypeInfo; const PropName: string;
    AKinds: TTypeKinds): PPropInfo;

===============================================================================
⊙ FindPropInfo 函數(shù)
===============================================================================
FindPropInfo 函數(shù)根據(jù)屬性名稱獲得屬性的 RTTI 指針,它只是在 GetPropInfo 函數(shù)的基礎上加上了錯誤檢查功能,如果沒有屬性 RTTI 信息,則觸發(fā) EPropertyError 異常。

function FindPropInfo(Instance: TObject; const PropName: string): PPropInfo;
function FindPropInfo(AClass: TClass; const PropName: string): PPropInfo;

===============================================================================
⊙ GetPropInfos 函數(shù)
===============================================================================
GetPropInfos 函數(shù)的功能是把一個類(class)所有屬性 RTTI 指針 PPropInfo 填充至傳入的參數(shù) PPropList 數(shù)組中。

注意:這個函數(shù)不負責分配該數(shù)組的內(nèi)容,使用前必須根據(jù)屬性的數(shù)量分配足夠的空間。該數(shù)組結(jié)束后必須清除分配的內(nèi)容。

  procedure GetPropInfos(TypeInfo: PTypeInfo; PropList: PPropList);

注:使用 GetPropList 實現(xiàn)相同的功能更方便。

===============================================================================
⊙ SortPropList 函數(shù)
==========================================

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多