To do this with records, you will create different types of records that have a common field in front, and then put the same fields in the shared record. Then you can simply type a pointer to a shared record to a pointer to a specific record, when necessary. For example:
type PGenericRec = ^GenericRec; GenericRec = Record RecType: Integer; end; PType1Rec = ^Type1Rec; Type1Rec = Record RecType: Integer; // Type1Rec specific fields... end; PType2Rec = ^Type2Rec; Type2Rec = Record RecType: Integer; // Type2Rec specific fields... end; PTypeNRec = ^TypeNRec; TypeNRec = Record RecType: Integer; // TypeNRec specific fields... end; var Recs: array of PGenericRec; Rec1: PType1Rec; Rec2: PType2Rec; RecN: PTypeNRec; I: Integer; begin SetLength(Recs, 3); New(Rec1); Rec1^.RecType := RecTypeForType1Rec; // fill Rec1 fields ... Recs[0] := PGenericRec(Rec1); New(Rec2); Rec2^.RecType := RecTypeForType2Rec; // fill Rec2 fields ... Recs[1] := PGenericRec(Rec2); New(RecN); Rec3^.RecType := RecTypeForTypeNRec; // fill RecN fields ... Recs[2] := PGenericRec(RecN); for I := 0 to 2 do begin case Recs[I]^.RecType of RecTypeForType1Rec: begin Rec1 := PType1Rec(Recs[I]); // use Rec1 as needed... end; RecTypeForType1Re2: begin Rec2 := PType2Rec(Recs[I]); // use Rec2 as needed... end; RecTypeForTypeNRec: begin RecN := PTypeNRec(Recs[I]); // use RecN as needed... end; end; end; for I := 0 to 2 do begin case Recs[I]^.RecType of RecTypeForType1Rec: Dispose(PType1Rec(Recs[I])); RecTypeForType2Rec: Dispose(PType2Rec(Recs[I])); RecTypeForTypeNRec: Dispose(PTypeNRec(Recs[I])); end; end; end;
As for serialization, you do not need TComponent for this. You can serialize records, you just need to do it manually. To record, first write the RecType value, and then write the following values for recording. To read, first read the RecType value, then create the appropriate record type for that value, then read the values related to the record in it:
interface type PGenericRec = ^GenericRec; GenericRec = Record RecType: Integer; end; NewRecProc = procedure(var Rec: PGenericRec); DisposeRecProc = procedure(Rec: PGenericRec); ReadRecProc = procedure(Rec: PGenericRec); WriteRecProc = procedure(const Rec: PGenericRec); function NewRec(ARecType: Integer): PGenericRec; procedure DisposeRec(var Rec: PGenericRec); procedure ReadRec(Rec: PGenericRec); procedure WriteRec(const Rec: PGenericRec); procedure RegisterRecType(ARecType: Integer; ANewProc: NewRecProc; ADisposeProc: DisposeRecProc; AReadproc: ReadRecFunc; AWriteProc: WriteRecProc); implementation type TRecTypeReg = record RecType: Integer; NewProc: NewRecProc; DisposeProc: DisposeRecProc; ReadProc: ReadRecProc; WriteProc: WriteRecProc; end; var RecTypes: array of TRecTypeReg; function NewRec(ARecType: Integer): PGenericRec; var I: Integer; begin Result := nil; for I = Low(RecTypes) to High(RecTypes) do begin with RecTypes[I] do begin if RecType = ARecType then begin NewProc(Result); Exit; end; end; end; raise Exception.Create('RecType not registered'); end; procedure DisposeRec(var Rec: PGenericRec); var I: Integer; begin for I = Low(RecTypes) to High(RecTypes) do begin with RecTypes[I] do begin if RecType = Rec^.RecType then begin DisposeProc(Rec); Rec := nil; Exit; end; end; end; raise Exception.Create('RecType not registered'); end; procedure ReadRec(var Rec: PGenericRec); var LRecType: Integer; I: Integer; begin Rec := nil; LRecType := ReadInteger; for I = Low(RecTypes) to High(RecTypes) do begin with RecTypes[I] do begin if RecType = LRecType then begin NewProc(Rec); try ReadProc(Rec); except DisposeProc(Rec); raise; end; Exit; end; end; end; raise Exception.Create('RecType not registered'); end; procedure WriteRec(const Rec: PGenericRec); var I: Integer; begin for I = Low(RecTypes) to High(RecTypes) do begin with RecTypes[I] do begin if RecType = Rec^.RecType then begin WriteInteger(Rec^.RecType); WriteProc(Rec); Exit; end; end; end; raise Exception.Create('RecType not registered'); end; procedure RegisterRecType(ARecType: Integer; ANewProc: NewRecProc; ADisposeProc: DisposeRecProc; AReadproc: ReadRecFunc; AWriteProc: WriteRecProc); begin SetLength(RecTypes, Length(RecTypes)+1); with RecTypes[High(RecTypes)] do begin RecType := ARecType; NewProc := ANewProc; DisposeProc := ADisposeProc; ReadProc := AReadProc; WriteProc := AWriteProc; end; end; end.
.
type PType1Rec = ^Type1Rec; Type1Rec = Record RecType: Integer; Value: Integer; end; procedure NewRec1(var Rec: PGenericRec); var Rec1: PType1Rec; begin New(Rec1); Rec1^.RecType := RecTypeForType1Rec; Rec := PGenericRec(Rec1); end; procedure DisposeRec1(Rec: PGenericRec); begin Dispose(PType1Rec(Rec)); end; procedure ReadRec1(Rec: PGenericRec); begin PType1Rec(Rec)^.Value := ReadInteger; end; procedure WriteRec1(const Rec: PGenericRec); begin WriteInteger(PType1Rec(Rec)^.Value); end; initialization RegisterRecType(RecTypeForType1Rec, @NewRec1, @DisposeRec1, @ReadRec1, @WriteRec1);
.
type PType2Rec = ^Type2Rec; Type2Rec = Record RecType: Integer; Value: Boolean; end; procedure NewRec2(var Rec: PGenericRec); var Rec2: PType2Rec; begin New(Rec2); Rec2^.RecType := RecTypeForType2Rec; Rec := PGenericRec(Rec2); end; procedure DisposeRec2(Rec: PGenericRec); begin Dispose(PType2Rec(Rec)); end; procedure ReadRec2(Rec: PGenericRec); begin PType2Rec(Rec)^.Value := ReadBoolean; end; procedure WriteRec2(const Rec: PGenericRec); begin WriteBoolean(PType2Rec(Rec)^.Value); end; initialization RegisterRecType(RecTypeForType2Rec, @NewRec2, @DisposeRec2, @ReadRec2, @WriteRec2);
.
type PTypeNRec = ^Type2Rec; TypeNRec = Record RecType: Integer; Value: String; end; procedure NewRecN(var Rec: PGenericRec); var RecN: PTypeNRec; begin New(RecN); RecN^.RecType := RecTypeForTypeNRec; Rec := PGenericRec(RecN); end; procedure DisposeRecN(Rec: PGenericRec); begin Dispose(PTypeNRec(Rec)); end; procedure ReadRecN(Rec: PGenericRec); begin PTypeNRec(Rec)^.Value := ReadString; end; procedure WriteRecN(const Rec: PGenericRec); begin WriteString(PTypeNRec(Rec)^.Value); end; initialization RegisterRecType(RecTypeForTypeNRec, @NewRecN, @DisposeRecN, @ReadRecN, @WriteRecN);
.
var Recs: array of PGenericRec; procedure CreateRecs; begin SetLength(Recs, 3); NewRec1(Recs[0]); PRecType1(Recs[0])^.Value : ...; NewRec2(Recs[1]); PRecType2(Recs[1])^.Value : ...; NewRecN(Recs[2]); PRecTypeN(Recs[2])^.Value : ...; end; procedure DisposeRecs; begin for I := 0 to High(Recs) do DisposeRec(Recs[I]); SetLength(Recs, 0); end; procedure SaveRecs; var I: Integer; begin WriteInteger(Length(Recs)); for I := 0 to High(Recs) do WriteRec(Recs[I]); end; procedure LoadRecs; var I: Integer; begin DisposeRecs; SetLength(Recs, ReadInteger); for I := 0 to High(Recs) do ReadRec(Recs[I]); end;