![]() |
Generischer Serialisierer
Guten Abend!
Mein Ziel ist es, Objekte (de)serialisieren zu können (zu XML-Dateien und TStreams). Ich weiß, es gibt das so Dinge wie die dpCollection, aber mich interessiert ein ganz anderer Ansatz: ![]() Zitat:
Ich habe mir das so vorgestellt, dass ich eine Schnittstelle ISerializable definiere, die von allen Objekten die serialisiert werden wollen implementiert werden muss, und eine Schnittstelle ISerializer, die von allen Serialisierern (XmlSerialisierer, BinärSerialisierer) implementiert werden muss. Das Problem: Wie serialisiere ich ein Objekt und wie deserialisiere ich ein Objekt? Wie soll das ganze funktionieren? Wie kann ich zur Laufzeit ein Objekt erstellen, von dem ich nur den Klassennamen als String weiß (beim Deserialisieren)? Vielen Dank, Andreas |
Re: Generischer Serialisierer
Zitat:
Delphi-Quellcode:
Das zeigt aber, dass du jede Klasse zum (De)serialisieren erst registrieren musst. Auch sonst wirst du schnell an die Grenzen der RTTI stoßen, der Aufwand ist IMHO nicht gerechtfertigt. Für einen wirklichen Serializer benötigst du etwas Größeres als die RTTI, wie z.B. Reflection von .NET. Und wie der Zufall es will, sieht das Serializing der FCL dem obigen Code verdammt ähnlich aus :wink: .
Result := TComponentClass(FindClass(ReadStr)).Create(nil);
[OT] Zitat:
[/OT] |
Re: Generischer Serialisierer
Danke für die Antwort!
Ich kenne die Serialisierung von .NET (bin auch C#-Programmierer). Deshalb ist die Ähnlichkeit der Quellcodes kein Zufall! :wink: Mir ist auch klar, dass ich in Delphi (mangels Runtime) nie so etwas wie die .NET Reflection haben werde. Aber der Ansatz von Maximov mit dem generischen Serialisierer interessiert mich sehr. Leider ist mir da noch zu wenig Information dabei, und ich würde gerne wissen, wie das ganz genau funktionieren soll. Meine Idee: Wenn ich im ISerializable Interface die Funktion "GetObjectData" habe, bekomme ich schon mal die zu serialisierenden Daten, die ich dann mit dem ISerializable Interface schreiben kann. Beim deserialisieren könnte ich ja mit dem Klassennamen eine Instanz erzeugen und wieder mit einer Funktion "WriteObjectData" des ISerializable Interfaces die ganzen Daten schreiben. Genau das Erstellen eines Objektes basierend am Klassennamen habe ich noch nicht geschafft. Mein Ansatz:
Delphi-Quellcode:
Interessant wäre hierbei auch noch, ob ich da ganz etwas anderes vorhabe, wie Maximov es vorgeschlagen hat, also ob ich seine Idee komplett missverstanden habe. :mrgreen:
var
Obj : TObject; ClassName: String; begin ... Obj := GetClass(ClassName).Create; if Obj is TButton then // Hier tritt dann eine Access-Violation auf: TButton(obj).Parent := self; //self = TForm EDIT: ![]() Danke, Andreas |
Re: Generischer Serialisierer
Obwohl ich, was Maximovs Ansatz betrifft, immer noch anstehe, habe ich mich weitergebildet und mir etwas überlegt:
Das ISerializable Interface in .net verlangt die Funktion "GetObjectData", mit der man sich die zu serialisierenden Daten holt. So etwas muss in Win32 auch möglich sein. Allerdings verlangt die Schnittstelle in .net auch einen Konstruktor mit den gleichen Argumenten, um das Objekt wieder deserialisieren zu können. Hier wird die ganze Geschichte für mich problematisch, da ich ja nicht schreiben kann:
Delphi-Quellcode:
Das zweite größere Problem ist: Wie erzeuge ich ein Objekt vom benötigten Typ, wenn ich nur die Eigenschaft ClassType oder ClassName des Objekts gegeben habe? Geht das überhaupt? Ich bräuchte das zum deserialisieren...
type
ITestInterface = Interface(IInterface) constructor Create({My arguments}); end; Vielen Dank, Andreas |
Re: Generischer Serialisierer
*push*
|
Re: Generischer Serialisierer
Zitat:
Zitat:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var ClassType: TClass; Instance: TControl; begin RegisterClass(TButton); ClassType := GetClass('TButton'); if ClassType = nil then ShowMessage('Klasse nicht gefunden') else if ClassType.InheritsFrom(TControl) then begin Instance := TControlClass(ClassType).Create(Self); if Instance = nil then ShowMessage('Instanz nicht erstellt') else Instance.Parent := Self; end else ShowMessage('Klasse kein Control'); end; Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
TSerializable = class
public constructor Create (info: TSerializationInfo, ...); abstract; Zitat:
|
Re: Generischer Serialisierer
Danke für die Antwort!
Zitat:
Danke für deine Vorschläge! Basisklasse ist für mich auch kein Problem. In deinem Code sehe ich ein ganz anderes Problem: Du registrierst eine Klasse (RegisterClass(TButton)), um dann später selbige mit GetClass() wieder zu holen. Ich weiß aber nicht welche Klasse es ist (außer, dass sie von meiner Basisklasse abgeleitet ist), weshalb ich sie vorher nicht registrieren kann (und deshalb kann ich sie mir per GetClass auch nicht holen). In meiner XML-Datei steht die Klasse ja nur als String drinnen... Vermutlich läuft das ganze darauf hinaus, dass ich beim Deserialisieren den Klassentyp übergeben muss und somit schon wissen muss, was ich deserialisiere. Was meint ihr? Vielen Dank, Andreas |
Re: Generischer Serialisierer
Das Problem hatte ich ja auch schon angesprochen. IMO gibt es nur zwei Möglichkeiten: Entweder man übergibt dem Deserializer den genauen Klassentyp, wie du schon geschrieben hast. Ich kann mir aber gut vorstellen, dass man diesen oft gar nicht / nur eine Basisklasse kennt. Dann gibt es nur noch einen Weg:
Der Deserializer muss einfach annehmen können, dass jede einzelne serialisierbare Klasse schon registriert wurde, z.B. im initialization-Abschnitt der Unit. Bei jeder Ableitung muss der Programmierer also ein RegisterClass(...) hinzufügen. |
Re: Generischer Serialisierer
Zitat:
![]() ...dazu musst du deine klassen aber in packages unterbringen, da der compiler sonst entfernen würde, weil er glaubt sie würden nicht verwendet. Mein generischer serialisierer ist eine unfertige idee gewesen, sollte aber mit ein bischen hirnschalz zu bewältigen sein. Ich versuch später mir was zu überlegen, bzw. das ein bischen auszuführen :) |
Re: Generischer Serialisierer
Danke für eure Antworten!
Wie du, Khabarakh, schon geschrieben hast, ist das ganze etwas viel Aufwand, nur um ein paar Objekte zu speichern. Ich denke, dass ich es anders machen werde: Eine TSerializableObject-Basisklasse mit...
In diesem Fall hätte ich das (De)Serialisieren erledigt, ohne dass ich diese Probleme habe. Der Grundgedanke des generischen Serialisierers ist mir schon klar, aber an der Ausführung happert es noch ein wenig. Ich wäre froh, wenn du, Maximov, mal ein kleines Beispiel posten oder in die Codelibrary stellen könntest. Vielen Dank, Andreas |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz