Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   RTTI und generische Listen (https://www.delphipraxis.net/205983-rtti-und-generische-listen.html)

hschmid67 6. Nov 2020 13:00

RTTI und generische Listen
 
Hallo zusammen,

ich finde leider nach einigen Stunden des Herumprobierens die Lösung nicht und hoffe, Ihr könnt mir helfen:

Ich habe eine Klasse mit einer Generischen Liste als Property, etwa so:

Delphi-Quellcode:
TMainClass = class
privat
  Fmeinarray: TList<TSubClass>;
public
  property meinarray: TList<TSubClass> read Fmeinarray write Fmeinarray;
end;
Nun möchte ich die aus einem Json-Array das meinarray erzeugen. Ich habe also eine Json-Datei, die etwa so aussieht:

Code:
[
  {"classname": "TSubClass", "feld1": "hallo"},
  {"classname": "TSubClass", "feld1": "welt"}
]
Es hat jedes Objekt des Arrays immer die gleiche TSubClass. Da ich in der Umwandungsfunktion verschieden Objekte verarbeiten möchte, habe ich den classname dort im Objekt gespeichert und baue über RTTI das Objekt dynamisch auf. Damit das eine Liste werden kann, dachte ich, ich könnte folgendes machen:

Delphi-Quellcode:
function ConvertJsonToList(const Jsonstring: string): TList<TObject>;


und könnte dann die TList<TObject> dem obigen Feld meinarray zuweisen. Aber das geht nicht, da offensichtlich TList<TSubClass> nicht mit TList<TObject> zuweisungskompatibel ist. Ok, soweit hab ich es verstanden und es ist ja auch nicht unlogisch.

Aber wie kann ich dann das erreichen, was ich brauche? Wie kann ich meine TList<DynamischErzeugtesObjekt> einer TList<TSubClass> zuweisen? Klar, wenn ich beim Umwandeln schon wüsste, welchen Typ die Liste hat, könnte ich auch hier mit einer generischen Funktion arbeiten:

Delphi-Quellcode:
function ConvertJsonToList<T>(const Jsonstring: string): TList<T>;


Aber das T ziehe ich ja erst aus dem Json-Feld classname.

Hat jemand eine Idee, oder kann mir meine Gedanken in die richtige Richtung lenken.

Herzliche Grüße
Harald

hschmid67 6. Nov 2020 15:28

AW: RTTI und generische Listen
 
Nun habe ich doch noch eine Lösung für mein Problem gefunden.

Der Schlüssel dazu ist, dass man die Typenüberprüfung von Delphi ausschalten muss, da sonst ja ein TObject nicht einem Property vom Typ TSubClass zugewiesen werden kann. (nur anders herum und das hilft hier nicht weiter - und ok, die Typensicherheit ist ein großer Vorteil von Delphi, aber an dieser Stelle, wüsste ich damit nicht weiter)

Um die Tpyenüberprüfung "quasi auszuschalten" kann man den Umweg über TValue nehmen. Pseudocode sähe dann in etwa so aus:

Delphi-Quellcode:
Value := CreateObjectByClassname(QualifiedClassname);


Dabei kann dann im TValue jedes Objekt gespeichert werden.

Um das dann einem Objektproperty zuweisen zu können, braucht man eine Funktion

Delphi-Quellcode:
SetPropertyValue(Object, PropertyName, Value);



Und wenn man vorher sichergeht, dass der QualifiedClassname genau dem PropertyName entspricht, geht man wegen der Typsicherheit auch kein Risiko ein.

Wenn man dann noch eine TList<T> mit Werten füllen möchte, braucht man noch eine Methode

Delphi-Quellcode:
InvokeMethod(Liste, 'add', [Value.AsObject]);



Ich weiß nicht, ob meine Vereinfachung so jetzt wirklich verständlich ist. Ich habe doch einige Stunden daran herumgetüftelt - und vielleicht ist für mich jetzt alles klar, was aus diesen paar Zeilen nicht ganz klar wird. Jedenfalls wollte ich meine Lösung hier beschreiben, damit jemand, der vielleicht ein ähnliches Problem hat, auf die richtige Spur kommen kann - oder auch nochmal nachfrägt. Dann kann ich gerne noch ausführlicher werden, oder meine oben in PseudoCode gehaltenen Funktionen ausführen.

Viele Grüße
Harald


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:29 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz