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;
{$M+} / {$TYPEINFO ON}:類別必須啟用型別資訊編譯指令(VCL 控件預設開啟),否則 ClassInfo 返回 nil。tkMethod 識別事件:在舊版 RTTI 中,事件表現為 PropType^.Kind = tkMethod 的屬性;新版(Delphi 2010+)可用 TRttiContext 更精確區分。GetMem/FreeMem 配對使用,防止洩漏;try..finally 確保釋放。GetPropInfos 返回包含所有祖先類別已發布屬性的完整列表。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(新版)能構建高度靈活的元驅動應用。