2
votes

The extended RTTI has the GetDeclaredProperties function which is exactly what i need, however i faced problems if i use the extended RTTI in multi-threading.

Therefore, i used GetPropList, but this gives me a list of all properties - not only published in the current class (or explicit stated).

i.e.

TBaseSettings = class(TPersistent)
published
    property Charset: string read FCharset write FCharset;
end;

TBasicSettings = class(TBaseSettings)
published
    property forums: Variant read fforums write fforums;
end;

TConcreteSettings = class(TBasicSettings)
published
    property forums; // <-- make it explicit visible: OK
    property prefix: Variant read fprefix write fprefix; // <-- OK
end;

I don't want to read the Charset property.

My first guess was to use a modified version of https://stackoverflow.com/a/1565686 to check for inheritance, but actually the forums property is also inherited.

Maybe this is not possible with the classic RTTI? I use Delphi 2010.

2
Use GetDeclaredPropetiesDavid Heffernan
I ended up changing the code that properties in the base class, which i don't want to read later in the GetPropList loop to be marked as public and not published. This is not exactly what i wanted to archive, but this works now for me :) Thanks you thumbs upgeskill

2 Answers

2
votes

In case it's convenient to have your code calling GetDeclaredPropList in a similar way to calling GetPropList, see below.

Edit: I've rewritten the code in Delphi 7 and I believe it should work in Delphi 2010, too (which I don't have at hand).

type
  PPropData = ^TPropData;

function AfterString(P: Pointer): Pointer;
begin
  Result := Pointer(NativeUInt(P) + (PByte(P)^ + 1));
end;

function GetPropData(TypeData: PTypeData): PPropData;
begin
  Result := AfterString(@TypeData^.UnitName);
end;

function NextPropInfo(PropInfo: PPropInfo): PPropInfo;
begin
  Result := AfterString(@PropInfo^.Name);
end;

procedure GetDeclaredPropInfos(TypeInfo: PTypeInfo; PropList: PPropList);
var
  TypeData: PTypeData;
  PropData: PPropData;
  PropInfo: PPropInfo;
  I: Integer;
begin
  TypeData := GetTypeData(TypeInfo);
  PropData := GetPropData(TypeData);
  FillChar(PropList^, Sizeof(PPropInfo) * PropData^.PropCount, 0);
  PropInfo := PPropInfo(@PropData^.PropList);
  for I := 0 to PropData^.PropCount - 1 do
  begin
    PropList^[I] := PropInfo;
    PropInfo := NextPropInfo(PropInfo);
  end;
end;

function GetDeclaredPropList(TypeInfo: PTypeInfo; out PropList: PPropList): Integer; overload;
begin
  Result := GetPropData(GetTypeData(TypeInfo))^.PropCount;
  if Result > 0 then
  begin
    GetMem(PropList, Result * SizeOf(Pointer));
    GetDeclaredPropInfos(TypeInfo, PropList);
  end;
end;

function GetDeclaredPropList(AObject: TObject; out PropList: PPropList): Integer; overload;
begin
  Result := GetDeclaredPropList(PTypeInfo(AObject.ClassInfo), PropList);
end;

// example usage:
var
  I, Count: Integer;
  PropList: PPropList;
  PropInfo: PPropInfo;
begin
  Count := GetDeclaredPropList(TypeInfo(TConcreteSettings), PropList);
  try
    for I := 0 to Count - 1 do
    begin
      PropInfo := PropList^[I];
      Writeln(PropInfo^.Name);
    end;
  finally
    FreeMem(PropList);
  end;
end.
0
votes
var
  TypeData: PTypeData;
  PropData: PPropData;
  PropInfo: PPropInfo;
  I: Integer;
begin
  TypeData := GetTypeData(TypeInfo(TConcreteSettings));
  PropData := GetPropData(TypeData);
  if Assigned(PropData) then
  begin
    PropInfo := @PropData^.PropList;
    for I := 0 to PropData^.PropCount - 1 do
    begin
      Writeln(PropInfo^.Name);
      PropInfo := NextPropInfo(PropInfo);
    end;
  end;
end;

For implementation of GetPropData and NextPropInfo see my other answer above.