Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - GetPropList: ClassInfo ist nil


baka0815 - Di 06.07.10 12:03
Titel: GetPropList: ClassInfo ist nil
Hallo zusammen,

ich möchte alle published-Eigenschaften eines Objekts herausfinden. Der folgende Code funktioniert allerdings nicht, weil der ClassInfo-Pointer nil ist. Wenn ich statt des markierten Codes die Zeile darüber verwende, funktioniert es problemlos.

Woran liegt das? Das Objekt das ich übergebe ist von TInterfacedObject abgeleitet und implementiert ein Interface. Aber auch wenn ich TObject.Create übergebe ist ClassInfo nil.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function GetProperties(Obj: TObject): TStringList;
var
  Count, Loop: Integer;
  List: TPropList;
begin
  Result := TStringList.Create;
  // Count := GetPropList(TypeInfo(TMeineKlasse), tkAny, @List);
  Count := GetPropList(PTypeInfo(Obj.ClassInfo), tkAny, @List);

  Result.BeginUpdate;
  for Loop := 0 to Pred(Count) do
    Result.Add(List[Loop]^.Name);
  Result.EndUpdate;
end;


BenBE - Di 06.07.10 12:30

Also bei mir tut


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function GetProperties(Obj: TObject): TStringList;
var
  Count, Loop: Integer;
  List: TPropList;
begin
  Result := TStringList.Create;
  Count := GetPropList(PTypeInfo(Obj.ClassInfo), tkAny, @List);

  Result.BeginUpdate;
  for Loop := 0 to Pred(Count) do
    Result.Add(List[Loop]^.Name);
  Result.EndUpdate;
end;


ohne Probleme (grad im Debugger nachgeschaut. Wobei: Deine TStringList ist nicht wirk,ich gegen Fehler geschützt. Try ... Except drum und im Fehlerfalle nil zurückgeben wäre praktisch ...


baka0815 - Di 06.07.10 13:09

Hmm, woran könnte das denn liegen? Wenn ich GetProperties(TObject.Create) aufrufe - Speichermanagement, etc. ist erst einmal egal, da es nur Testcode ist - dann wird mir in GetProperties angezeigt, dass Obj.ClassInfo ein nil-Pointer ist.

Ich habe mir dafür sicherheitshalber den Code von dir raus kopiert.

Die Funktion ClassInfo macht bei mir folgendes:

Delphi-Quelltext
1:
  Result := PPointer(Integer(Self) + vmtTypeInfo)^;                    


Ich habe schon versucht, das so nachzustellen. Ich bekomme auch eine Adresse (PPointer(Integer(Self) + vmtTypeInfo)), wenn ich diese mit ^ dereferenziere, bekomme ich aber wieder nil -> stellt sich mir die Frage warum...


BenBE - Di 06.07.10 13:17

TObject hat keine published-Properties. Du brauchst eine Klasse, die von TPersistent abgeleitet ist.

Hab es it TApplication probiert.


baka0815 - Di 06.07.10 14:05

Wenn ich TPersistent.Create statt TObject.Create verwende funktioniert alles bestens, also müssen auch meine Klassen entsprechend geändert werden und nicht mehr von TInterfacedObject, sondern von TInterfacedPersistent erben, korrekt?

Zumindest funktioniert das ganze so.

Gibt es für dieses Verhalten (Interface != Objekt, TObject != TPersistent) einen vernünftigen Grund?


BenBE - Di 06.07.10 17:21

Ja ;-) Und der ist sogar dokumentiert ;-)

TObject ist im Status $H- compiliert und besitzt damit keine Typen-Informationen. Erst TPersistent ODER alle davon abgeleiteten Klassen besitzen diese. Für eigene, von TObject abgeleitete Klassen, kann man den $H+-Status aber auch manuell setzen.

Mehr Details dazu in der System.pas bei der Deklaration von TPersistent ...


baka0815 - Mi 07.07.10 13:02

$H [http://www.delphibasics.co.uk/RTL.asp?Name=$H] hat aber nichts mit den Typeninformationen zu tun!?

Meinst du vielleicht $M [http://docwiki.embarcadero.com/RADStudio/de/Laufzeit-Typinformationen_%28Delphi%29]? Das wird aber doch automatisch hinzugefügt sobald ich eine published-Eigenschaft deklariere?!

Und da meine Klasse published-Eigenschaften besitzt, bekomme ich die Info dass {$M+} für RTTI hinzugefügt wird und trotzdem funktioniert es nicht wenn ich von TObject (bzw. TInterfacedObject) ableite - von TPersistent (bzw. TInterfacedPersistent) funktioniert.


guinnes - Mi 07.07.10 13:09

user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
Und da meine Klasse published-Eigenschaften besitzt, bekomme ich die Info dass {$M+} für RTTI hinzugefügt wird und trotzdem funktioniert es nicht wenn ich von TObject (bzw. TInterfacedObject) ableite - von TPersistent (bzw. TInterfacedPersistent) funktioniert.
Published macht doch erst ab TPersistent Sinn, da TObject das Streaming-System von Delphi noch nicht unterstützt


baka0815 - Mi 07.07.10 14:13

Ich brauche das Streaming-System ja eigentlich nicht und ich möchte die Klassen auch nicht serialisieren oder ähnliches, sondern nur per RTTI auf die Eigenschaften zugreifen. Ich finde es eh komisch, dass eben nur auf die published Eigenschaften zugegriffen werden kann (bin da von Java verwöhnt).


BenBE - Mi 07.07.10 14:19

Jup, meinte $M; brauch die so selten ;-)

TPersistent implementiert das Streaming-System, das ist richtig. TPErsistent ist aber auch die erste Klasse, die Property-Typinfos besitzt (eben wegen diesem Schalter).

Für andere Klassen werden zwar die Published-Properties als Properties generiert, der Streaming-Mechanismus funktioniert aber nicht, weil eben die erweiterten Klassen-Infos nicht erzeugt werden

Wenn Du deine eigene Ableitung auch im Status $M+ generierst, sollte es auch mit einer von TObject abgeleiteten Klasse gehen.