首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi RTTI 實戰:獲取物件屬性與事件列表的通用函數

     編輯:Delphi

Delphi 執行時類型資訊(RTTI)讓程式能在運行時檢查類別的屬性、方法、事件等元數據。本文提供一個通用函數 GetPropertyAndEventList,演示如何使用 TypInfo 單元遍歷任意物件的已發布屬性與事件,並輸出排序後的名稱列表。

核心代碼

uses TypInfo;  { 必須引用 }

function GetPropertyAndEventList(Obj: TObject; PropList, EventList: TStringList): Boolean;
var
  TypeInfo: PTypeInfo;       { 類型資訊指標 }
  TypeData: PTypeData;       { 類型資料指標 }
  PropListArr: PPropList;    { 屬性資訊陣列指標 }
  Count, Size, I: Integer;
begin
  Result := False;
  if Obj = nil then Exit;

  { 1. 取得類別的 TypeInfo }
  TypeInfo := Obj.ClassInfo;
  if TypeInfo = nil then Exit;  { 未啟用 $M+ 或無 published 成員 }

  { 2. 取得類別資料(含屬性計數) }
  TypeData := GetTypeData(TypeInfo);
  Count := TypeData.PropCount;
  if Count = 0 then
  begin
    Result := True;
    Exit;
  end;

  { 3. 分配屬性陣列緩衝區 }
  Size := SizeOf(TPropInfo);
  GetMem(PropListArr, Size * Count);
  try
    { 4. 填充屬性陣列 }
    GetPropInfos(TypeInfo, PropListArr);

    { 5. 遍歷區分屬性與事件 }
    for I := 0 to Count - 1 do
    begin
      with PropListArr[I]^ do
      begin
        if PropType^.Kind = tkMethod then
          EventList.Add(Name)   { 事件本質是方法型別屬性 }
        else
          PropList.Add(Name);
      end;
    end;

    { 6. 排序輸出 }
    PropList.Sort;
    EventList.Sort;
    Result := True;
  finally
    FreeMem(PropListArr);
  end;
end;

測試表單代碼

procedure TForm1.Button1Click(Sender: TObject);
var
  Props, Events: TStringList;
begin
  Props := TStringList.Create;
  Events := TStringList.Create;
  try
    Memo1.Clear;
    Memo2.Clear;
    GetPropertyAndEventList(Self, Props, Events);  { Self = 當前表單 }
    Memo1.Lines := Props;   { 顯示屬性 }
    Memo2.Lines := Events;  { 顯示事件 }
  finally
    Props.Free;
    Events.Free;
  end;
end;

關鍵點解析

  1. {$M+} / {$TYPEINFO ON}:類別必須啟用型別資訊編譯指令(VCL 控件預設開啟),否則 ClassInfo 返回 nil。
  2. tkMethod 識別事件:在舊版 RTTI 中,事件表現為 PropType^.Kind = tkMethod 的屬性;新版(Delphi 2010+)可用 TRttiContext 更精確區分。
  3. 記憶體管理:GetMem/FreeMem 配對使用,防止洩漏;try..finally 確保釋放。
  4. 繼承鏈自動合併:GetPropInfos 返回包含所有祖先類別已發布屬性的完整列表。

新版 RTTI(Delphi 2010+)寫法對比

uses System.Rtti;

procedure ListPropsEventsNew(Obj: TObject; Props, Events: TStringList);
var
  Ctx: TRttiContext;
  Typ: TRttiType;
  Prop: TRttiProperty;
begin
  Ctx := TRttiContext.Create;
  try
    Typ := Ctx.GetType(Obj.ClassType);
    for Prop in Typ.GetProperties do
    begin
      if Prop.PropertyType.TypeKind = tkMethod then
        Events.Add(Prop.Name)
      else
        Props.Add(Prop.Name);
    end;
  finally
    Ctx.Free;
  end;
end;

新版 API 更強型別、支援泛型、屬性特性(Attribute)查詢,建議新專案優先使用。

應用場景

  • 物件檢查器/屬性網格自動生成。
  • 序列化框架自動發現可序列化屬性。
  • 動態表單構建、腳本綁定、插件系統。
  • 單元測試驗證物件契約完整性。

常見問題

現象原因解決
ClassInfo = nil類別未標記 {$M+} 或無 published 區段在類別定義前加 {$M+} 或確保有 published
事件未列出事件未發布(在 public/protected)將事件移至 published 區段
屬性重複繼承鏈中同名屬性遮蔽屬性列表已包含繼承屬性,屬正常行為

RTTI 是 Delphi 動態能力的核心,善用 TypInfo(舊版)或 System.Rtti(新版)能構建高度靈活的元驅動應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved