Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Dynamisches Record? (https://www.delphipraxis.net/46299-dynamisches-record.html)

Thanatos81 22. Mai 2005 13:09


Dynamisches Record?
 
Hi DP'ler!

Hab mir vorgenommen eine eigen Komponente für typisierte Dateien zu erstellen, da ich diese oft benutze. Die funktioniert soweit auch ganz gut (Next,Prior,BoF,EoF,RecNo,RecordCount,Append,Edit, Delete).

Allerdings brauch ich ja zum Ansprechen einer typisierten Datei das Format der selbigen in Form eines Record-Typen, also z.B:
Delphi-Quellcode:
type
  TBlubb = record
    LfdNr  : Integer;
    KdNr   : Integer;
    Name   : String[50];
    Vorname : String[50];
end;

var
 IO : file of TBlubb;
Da ich nun aber eine allg. Komponente erstellen möchte habe ich mir folgendes überlegt: Die Felddefinitionen lege ich inner einer INI oder etwas ähnlichem ab. jetzt kommen wir zu meinem Problem: Gibts in Delphi etwas in der Richtung von dynamischen Records? Also das ich die Header-Datei einlese und dann erst die Deklaration folgen lasse?

Schönen Dank im Voraus,

r2c2 22. Mai 2005 13:36

Re: Dynamisches Record?
 
Das Einzige, was mir so auf die Schnelle einfällt wäre, statt n record ne class zu nehmen und die deiner Komponente dann zu übergeben. Dann kannst du mit TypeCasts arbeiten. Keine Ahnung hab ich noch nie gemacht. Oder du nimmst n Pointer und dann auch weiter mit TypeCast. :gruebel:
Hm... Probiers einfach mal aus, oder wart, bis jemand postet der davon mehr versteht als ich.

mfg

Christian

[edit]
P.S.: Ich personlich würde ne Klasse bevorzugen. Die müllen dann das Formulau nicht so zu und du kannst die class/den Pointer dem Creator übergeben. Aber das ist Geschmacksache...
[/edit]

Chewie 22. Mai 2005 13:38

Re: Dynamisches Record?
 
Mit Records geht das nicht, da die Namen der Felder im Kompilar gar nicht mehr existieren. Du könntest aber z.B. eine HashMap verwenden, in der due über den Schlüssel der Daten an deine Werte rankommst.

Robert_G 22. Mai 2005 17:17

Re: Dynamisches Record?
 
Wenn es mit etwas Umwegen gehen darf, wäre eine TList-Ableitung möglich.
Diese würde den ItemTypen bekommen und könnte damit sofort loslegen. (die Felder einer Klasse sind nichts weiter als ein Record ;) )

Hier erstmal das FileOfClass-Dingsbums...
Delphi-Quellcode:
unit uFileOfClass;

interface
uses
  Classes,
  Contnrs;

type
  TFileOfClass = class(TObjectList)
  private
    fItemType: TClass;
  protected
    procedure WriteItemToStream(const aItem: TObject; aStream: TStream); virtual;
    function ReadItemFromStream(aStream: TStream): TObject; virtual;
  public
    property ItemType: TClass read fItemType;

    procedure SaveToStream(aStream: TStream); virtual;
    procedure LoadFromStream(aStream: TStream); virtual;

    procedure SaveToFile(const aFileName: string); virtual;
    procedure LoadFromFile(const aFileName: string); virtual;

    constructor Create(aItemType: TClass; aOwnsObjects: Boolean = True); virtual;
  end;


implementation
uses
  SysUtils;

{ TFileOfClass }

constructor TFileOfClass.Create(aItemType: TClass; aOwnsObjects: Boolean);
begin
  inherited Create(aOwnsObjects);
  fItemType := aItemType;
end;

procedure TFileOfClass.LoadFromFile(const aFileName: string);
var
  Stream              : TStream;
begin
  Stream := TFileStream.Create(aFileName, fmOpenRead);
  try
    LoadFromStream(Stream);
  finally
    Stream.Free();
  end;
end;

procedure TFileOfClass.LoadFromStream(aStream: TStream);
begin
  while aStream.Position < aStream.Size do
    Add(ReadItemFromStream(aStream));
end;

function TFileOfClass.ReadItemFromStream(aStream: TStream): TObject;
begin
  Result := ItemType.NewInstance();
  aStream.Read(Pointer(Result)^, ItemType.InstanceSize - SizeOf(Pointer));
end;

procedure TFileOfClass.SaveToFile(const aFileName: string);
var
  Stream              : TStream;
begin
  Stream := TFileStream.Create(aFileName, fmCreate);
  try
    SaveToStream(Stream);
  finally
    Stream.Free();
  end;
end;

procedure TFileOfClass.SaveToStream(aStream: TStream);
var
  i                   : Integer;
begin
  for i := 0 to Count - 1 do
  begin
    WriteItemToStream(Items[i], aStream);
  end;
end;

procedure TFileOfClass.WriteItemToStream(const aItem: TObject; aStream: TStream);
begin
  aStream.Write(Pointer(aItem)^, ItemType.InstanceSize - SizeOf(Pointer));
end;

end.
Ist nicht schön.... aber was kann in Verbindung mit typisierten Dateien schon schön sein. :mrgreen:
Dein "record" sähe wohl so aus.
Delphi-Quellcode:
type
   TBlubbClass = class
   private
      fLfdNr: Integer;
      fKdNr: Integer;
      fName: myShortString;
      fVorname: myShortString;
   published
      property LfdNr: Integer read fLfdNr write fLfdNr;
      property KdNr: Integer read fKdNr write fKdNr;
      property Name: myShortString read fName write fName;
      property Vorname: myShortString read fVorname write fVorname;
   end;
Reinschreiben könntest du es so:
Delphi-Quellcode:
var
  myList              : TFileOfClass;
  Blubb               : TBlubbClass;
begin
  myList := TFileOfClass.Create(TBlubbClass);
  try
    Blubb := TBlubbClass.Create();
    Blubb.LfdNr := 1;
    Blubb.KdNr := 10;
    Blubb.Name := 'Schulz';
    Blubb.Vorname := 'Hans';

    myList.Add(Blubb);

    Blubb := TBlubbClass.Create();
    Blubb.LfdNr := 2;
    Blubb.KdNr := 20;
    Blubb.Name := 'Müller';
    Blubb.Vorname := 'Bert';

    myList.Add(Blubb);

    myList.SaveToFile('Miep.txt');
  finally
    myList.Free();
  end;
end;
Auslesen wäre so möglich:
Delphi-Quellcode:
var
  myList              : TFileOfClass;
  i                   : Integer;
begin
  myList := TFileOfClass.Create(TBlubbClass);
  try
    myList.LoadFromFile('Miep.txt');

    for i := 0 to myList.Count - 1 do
      with TBlubbClass(myList[i]) do
        ListBox1.Items.Add(Name + ', ' + Vorname);

  finally
    myList.Free();
  end;
end;
Dumm ist nur, dass es eigentlich totaler Blödsinn ist. :mrgreen:
Ändere den "record" zu einer Ableitung von TCollectionItem und schon kannst du auch strings und alles andere benutzen.
Anstatt der TFileOfClass würde die dpCollectiondpCollection ins Spiel kommen.
Bist du auf Kompatibilität zu ekligen typisierten Dateien angewiesen musst du wohl den Weg oben gehen (und hoffen, dass der Compiler die Felder nicht irgendwann intern verdreht).
Bist du es nicht sehe ich keine Ausrede weiterhin typisierte Dateien zu nehmen. ;)
Delphi-Quellcode:
type
   TBlubbClass = class(TCollectionItem)
   private
      fLfdNr: Integer;
      fKdNr: Integer;
      fName: string;
      fVorname: string;
   published
      property LfdNr: Integer read fLfdNr write fLfdNr;
      property KdNr: Integer read fKdNr write fKdNr;
      property Name: string read fName write fName;
      property Vorname: string read fVorname write fVorname;
   end;

Thanatos81 22. Mai 2005 20:43

Re: Dynamisches Record?
 
Das is mal ne Menge Input! Danke erst mal! Werde mit das morgen mal in aller Ruhe zu Gemüte führen, vor allem auch die DPCollection.

Ich hab bisher typisierte Dateien als Ersatz für Datenbanken genommen. Vorteil ist halt, dass die Dinger unschlagbar schnell sind und auch keinerlei Lizenzen für irgendwelche Server voraussetzen. Nachteil war bisher der immer wiederkehrende Aufwand die im Prinzip gleichen Sachen nochmal zu Proggen. Deswegen die Idee mit der Komponenten und erst zur Laufzeit deklarierten records.

Aber wenn die DPCollection das gleiche bietet, warum sollte ich dann das Rad neu erfinden, gelle?

Aber eine Frage noch Robert_G: Was findest du an typisierten Dateien eklig(abgesehen von der Handhabung für den Programmierer)?

Schönen Abend noch,

Robert_G 22. Mai 2005 21:42

Re: Dynamisches Record?
 
Zitat:

Zitat von Thanatos81
Aber eine Frage noch Robert_G: Was findest du an typisierten Dateien eklig(abgesehen von der Handhabung für den Programmierer)?

Sie zwingen dir Records und fixed sized strings auf. Außerdem sind sie nicht aufwärtskompatibel, es wird sogar knallen wenn der nächste Compiler deinen Record etwas anders umsetzt. (unwahrscheinlich, aber möglich)
Der einzige Nachteil der DP Collection ist, dass ihr Vorgänger und der Itemtyp in Classes.pas deklariert ist. (mehr als beschissen, wenn man Klasssen in Packages auslagert :? )
Sie ist aber langsamer als ein file of murks. Schließlich kann sie nicht einfach Daten in eine primitive Struktur schieben. Sie wird alle published properties speichern. (bzw auch andere, wenn man Delphi-Referenz durchsuchenDefineProperties benutzt)

Robert_G 22. Mai 2005 22:03

Re: Dynamisches Record?
 
noch eins... Kann TFileOfClass eine typ. Datei einlesen, die du mit einem gleich strukturierten Record erzeugt hattest?
Das hatte ich einfach angenommen, aber nicht getestet. :oops:

jbg 22. Mai 2005 22:35

Re: Dynamisches Record?
 
Zitat:

Zitat von Robert_G
Der einzige Nachteil der DP Collection ist, dass ihr Vorgänger und der Itemtyp in Classes.pas deklariert ist. (mehr als beschissen, wenn man Klasssen in Packages auslagert :? )

Ja, ich nehme mir auch immer vor bei meinen C++ Programmen auf die Runtime zu verzichten um nicht von der msvcrtxx.dll abzuhängen. :roll:

Robert_G 22. Mai 2005 22:38

Re: Dynamisches Record?
 
Zitat:

Zitat von jbg
Zitat:

Zitat von Robert_G
Der einzige Nachteil der DP Collection ist, dass ihr Vorgänger und der Itemtyp in Classes.pas deklariert ist. (mehr als beschissen, wenn man Klasssen in Packages auslagert :? )

Ja, ich nehme mir auch immer vor bei meinen C++ Programmen auf die Runtime zu verzichten um nicht von der msvcrtxx.dll abzuhängen. :roll:

Die ist aber schon auf dem Zielsystem vorhanden. ;)
Aber 1.5 MB VCL.dcp mitzuliefern verkneife ich mir dann doch solange es nur 1 oder 2 Echsen sind. Die installiert werden.
Bei mehr ist es IMHO sogar sinnvoll die VCL als package zu nehmen. ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:57 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