Hi,
du kannst das auch selber machen.
Der Aufbau deines Stream sieht immer so aus:
Klassenname als String
Daten zu diesem Objekt
Klassenname als String
Daten zu diesem Objekt
Dh. du speicherst in deinem Stream auch die Klassenname -> Self.ClassName als ShortString -> String der nur 255 Zeichen speichern kann, dafür in String[0] die Länge.
Fehlt noch der Punkt wie man von einem solchen String zurück zu einer Klasse kommt die man instanzieren kann. Dazu gehts du exakt so vor wie die
VCL. Diese verwaltet eine TList -> RegisteredClasses und zwei Prozeduren -> RegisterClasses(Classes: array of TClass) und Funktion GetClass(const ClassName: String): TClass;
In deinem Code rufst du nun RegisterClasses([TPoint, TKante, TFlaeche]) in der Initialization Sektion auf.
Deine Stream-Leses-Routine liest erstmal einen ShortString aus dem Stream. Dann wird mit GetClass(NameAusDemStream).Create eine Instance erzeugt. Dieser Instanze übergibst du die Kontrolle des Streams damit sie nun ihre Daten auslesen kann.
Alle deine Klassen sollten von eniner Basisklasse abgeleitet sein, zb. TMyBaseClass.
Delphi-Quellcode:
type
TMyBaseClass = class
protected
procedure LoadFromStream(Stream: TStream); virtual;
end;
TPoint = class(TMyBaseClass);
TKante = class(TMyBaseClass);
procedure LoadObjects(List: TList; Stream: TStream);
function ReadClassName: ShortString;
begin
Stream.Read(Result[0], SizeOf(Result[0]));
Stream.Read(Result[1], Ord(Result[0]));
end;
var
Instance: TMyBaseClass;
begin
while Stream.Position < Stream.Size do
begin
Instance := (GetClass(ReadClassName) as TMyBaseClass).Create;
Instance.LoadFromStream(Stream);
List.Add(Instance);
end;
end;
procedure SaveObjects(List: TList; Stream: TStream);
var
I: Integer;
S: ShortString;
begin
for I := 0 to List.Count -1 do
with List[I] as TMyBaseClass do
begin
S := ClassName;
Stream.Write(S[0], Ord(S[0]) +1);
SaveToStream(Stream);
end;
end;
initialization
RegisterClasses([TPoint, TKante, TFlaeche,...]);
end.
Ist natürlich nur ein grobes Beispiel und man kann noch einiges verbessern. Statt zb. den langen Klasssennamen zu speichern köntest du auch zu jeder Klasse eine eigene ID erzeugen und diese dann als Byte,Word oder LongWord abspeichern. Das macht deinen Stream kompakter, besonders falls du tausende solcher Objekte speichern möchtest.
Bei einer meiner Klassen (hierarisch, sortierter Node Baum) mache ich es so das ich als erstes alle Klassennamen der verwendeten Objekte in den Stream speichere. Diese Liste dient nun als Lookuptabelle um einen Klassennamen=Klasse eine ID zu geben. Diese ID ist nichts anderes als der Index in diese Liste. Man speichert also zb. einen Baum aus 10000 Objekten mit 10 unterschiedlichen Klassen so das man als erstes eine sortierte Liste aus Strings=Klassenamen in den Stream speichert. Das sind also 10 Strings. Die nachfolgenden Klassen haben dann eine 1 Byte ID, der Index in diese Liste an der der Klassenname steht.
Somit sparst du viel Speicherplatz, weist von Anfang an welche Klassen im Stream gespeichert sind, und zur Laufzeit kannst du die Klasse einfach in dieser Liste direkt nachschlagen, ein Objeckt wird ja über seinen Byte-Index aus dem Stream identifiziert.
Die Verweise auf dpCollection sind gut gemeint, aber ich meine das du mit wenigen Zeilen Source selber schneller bist und auch was dabei lernst.
Gruß Hagen