Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Records dynamisch verschachteln (https://www.delphipraxis.net/115335-records-dynamisch-verschachteln.html)

psycore 10. Jun 2008 15:23


Records dynamisch verschachteln
 
Hallo,


ich programmiere derzeit eine Client/Server Anwendung und habe mir überlegt, die Kommunikation über Records laufen zu lassen, welche ineinander verschachtelt sind. Einen Standardtyp mit einigen Arrays festzulegen ist mir zu unflexibel.

Mal ein Beispiel damit ihr seht was ich meine:

Delphi-Quellcode:
type
   THauptrecord = record
     id: Integer;
     SubRec: TRecord;
   end;

type
   TSubRec1 = record
     Value1: Integer;
     Value2: String;
     [...]
   end;

type
   TSubRec2 = record
     Value1: Integer;
     Value2: String;
     [...]
   end;
Soviel zur deklaration. Beim Versenden:

Delphi-Quellcode:
Hauptrecord.id := 5;
Hauptrecord.SubRec := SubRec2;

SubRec2.Value1 := 17;
SubRec2.Value2 := 'bla';
...und dann wird Hauptrecord an den Server geschickt.


Das Problem: TRecord existiert nicht :mrgreen:

Gibts eine Möglichkeit sowas zu machen oder bin ich mit der ganzen Idee am Holzweg?


mfg & danke

psycore

tomsel 10. Jun 2008 15:34

Re: Records dynamisch verschachteln
 
Für deinen Zweck könnte vielleicht eher ein varianter Record in Frage kommen??

gammatester 10. Jun 2008 15:35

Re: Records dynamisch verschachteln
 
Zitat:

Zitat von psycore
Das Problem: TRecord existiert nicht

Da hat der Compiler doch wohl auch recht :) Zumindestest hast Du uns die Deklaration auch nicht verraten.

Du kannst mal unter Variant parts in records in der Hilfe nachsehen und prüfen, ob Dir diese weiterhelfen.

Gruß Gammatester

TeronG 10. Jun 2008 15:35

Re: Records dynamisch verschachteln
 
Du hast aber schon sowas wie
Delphi-Quellcode:
Var
  Hauptrecord : THauptrecord;

...

SetLength(Hauptrecord,0815);
SetLength(Hauptrecord.SubRec,4711);
gemacht oder?

Namenloser 10. Jun 2008 15:38

Re: Records dynamisch verschachteln
 
Kann man echt Längen von Records manuell setzen oO? Ich jedenfalls würde dir in disem Fall eindeutig zu Klassen und Streams raten. Mit Records wird das hier nur unnötig kompiziert.

psycore 10. Jun 2008 15:52

Re: Records dynamisch verschachteln
 
Zitat:

Zitat von TeronG
Du hast aber schon sowas wie
Delphi-Quellcode:
Var
  Hauptrecord : THauptrecord;

...

SetLength(Hauptrecord,0815);
SetLength(Hauptrecord.SubRec,4711);
gemacht oder?


Nein, hätte mich das irgendwie weiter gebracht? :-]


Wenn ich eure Reaktionen so lese, scheint mir es ginge auf diese Weise nicht, richtig?
Naja, werde mir dann erstmal variante Records näher anschauen.


psycore

psycore 11. Jun 2008 11:00

Re: Records dynamisch verschachteln
 
Ach Mist :(


Delphi-Quellcode:
type
   THauptrecord = record
    case Id: integer of        //Eigentlicher Datenrecord
      1: (SubRec1: TSubRec1);
      2: (SubRec2: TSubRec2);
   end;

type
   TSubRec1 = record
     Value1: Integer;
     Value2: String;
   end;

type
   TSubRec2 = record
     Value1: Integer;
     Value2: String;
   end;

Typ 'TSubRec1' benötigt Finalization - nicht im varianten Record erlaubt.

Und nu? :gruebel:

tomsel 11. Jun 2008 11:31

Re: Records dynamisch verschachteln
 
Oh, dann funktioniert das nur mit Strings fester Länge. Aber die benötigst du ohnehin, wenn du das Ganze als Packet über's Netz schicken willst (?).

gammatester 11. Jun 2008 12:27

Re: Records dynamisch verschachteln
 
Zitat:

Zitat von psycore
Ach Mist
Typ 'TSubRec1' benötigt Finalization - nicht im varianten Record erlaubt.

Und nu? :gruebel:

Warum willst Du denn Finalization im varianten Record machen? (Was immer das bedeuten soll, geht das bei den 'neuen' extended Records)

Selbstverständlich kann man Teile eines varianten Records im Finalizationteil ansprechen (zumindest bei D3 bis D10):

Delphi-Quellcode:
type
  vr = record
        fix: integer;
        case integer of
          1: (v1: integer);
          2: (v2: boolean);
        end;
var
  xx: vr;

Initialization
  fillchar(xx, sizeof(xx), 0);
finalization
  xx.fix := 42;
  xx.v1  := 7;
  xx.v2  := false;
end.
Gruß Gammatester

sirius 11. Jun 2008 12:32

Re: Records dynamisch verschachteln
 
@gammatester:
Es geht darum, dass in varianten Records keine dynamischen Variablen enthalten sein drüfen (also Strings oder dynamische Arrays). Das hat nix mit dem Finalization-Abschnitt einer Unit zu tun, sondern mit dem Ende des Gültigkeitsbereiches einer Variable.

gammatester 11. Jun 2008 12:44

Re: Records dynamisch verschachteln
 
Zitat:

Zitat von sirius
@gammatester:
Es geht darum, dass in varianten Records keine dynamischen Variablen enthalten sein drüfen (also Strings oder dynamische Arrays). Das hat nix mit dem Finalization-Abschnitt einer Unit zu tun, sondern mit dem Ende des Gültigkeitsbereiches einer Variable.

OK, was dazu gelernt. Allerdings ist das Dynamische bei Kommunikation über Records in der Regel doch wohl eher die Ausnahme, bzw. würde über spezielle Prozeduren laufen, die Pointer und Länge verwerten.

(Wenn man in seine Records string durch string[xx] ersetzt, wird's compiliert)

Gruß Gammatester

psycore 11. Jun 2008 12:46

Re: Records dynamisch verschachteln
 
Ich versteh aber nicht warum das nicht geht.

Zitat:

Die Teile hinter case teilen sich denselben Speicherbereich. Der Compiler reserviert so viel Platz wie die größte Variante benötigt. Deshalb können auch variante Records in typisierten Dateien verwendet werden.

*edit*

Zitat:

(Wenn man in seine Records string durch string[xx] ersetzt, wird's compiliert)
Heureka!

gammatester 11. Jun 2008 12:52

Re: Records dynamisch verschachteln
 
Zitat:

Zitat von psycore
Ich versteh aber nicht warum das nicht geht.

Zitat:

Die Teile hinter case teilen sich denselben Speicherbereich. Der Compiler reserviert so viel Platz wie die größte Variante benötigt. Deshalb können auch variante Records in typisierten Dateien verwendet werden.

Wahrscheinlich wegen der Compilermagic und dem Verwischen von Pointern mit arrays/strings. Es wird wahrscheinlich der Pointer in den Record eintragen, aber die eigentliche Länge der Strings/Arrays ist zum Zeitpunkt des Kompilierens nicht bekannt.

Das ist anders, wenn man string[200] o.ä. nimmt, dann werden zB 201 chars reserviert.

Gammtester

Apollonius 11. Jun 2008 19:47

Re: Records dynamisch verschachteln
 
Nein, der Punkt ist, dass am Ende jeder Prozedur, die direkt oder indirekt Ansistrings, dynamische Arrays, Variants oder Interfaces verwendet, aufgeräumt werden muss, damit der Referenzzähler stimmt, eben im Gegensatz zu einfachen Typen oder Objektinstanzen. In varianten Records weiß Delphi dann natürlich nicht, ob jetzt ein String oder ein Integer im Record steht, und entsprechend, ob ein Referenzzähler aktualisiert werden muss.

NickelM 12. Jun 2008 00:01

Re: Records dynamisch verschachteln
 
Also mir kommt dass so vor, als das in eine Endlose diskusion geht.

Ich würde es auch mit Streams versuchen. Einen Record vieleicht, denn du dan in den Stream schreibst und dan rausliest.

spaxxn 12. Jun 2008 07:03

Re: Records dynamisch verschachteln
 
Darf man fragen, welchen Weg der Kommunikation zwischen Client und Server du dir gedacht hast?

Bedenke dabei, dass Client und Server in unterschiedlichen Adressbereichen laufen... Ergo wirst du dir bestimmt überlegt habe, wie die Daten vom Client zum Server und anders herum gelangen.

psycore 12. Jun 2008 14:52

Re: Records dynamisch verschachteln
 
Client:
Delphi-Quellcode:

procedure TMainForm.ConnectBtnClick(Sender: TObject);
var
  buffer: TIdBytes;
begin
  MsgRec.id := 1;
  MsgRec.auth.version := '0.1';
  MsgRec.auth.nickname := nick_input.text;
  MsgRec.auth.password := pw_input.text;

  try
    Client.Connect;
    buffer := RawToBytes(MsgRec, SizeOf(TMsgRec));
    Client.IOHandler.Write(buffer);
  except
    ShowMessage('Verbindung konnte nicht hergestellt werden');
  end;
end;
Server:
Delphi-Quellcode:



procedure TMainForm.ServerExecute(AContext: TIdContext);
var
  MsgRec: TMsgRec;
  buffer: TIdBytes;
begin
  AContext.Connection.IOHandler.ReadBytes(buffer, SizeOf(TMsgRec));
  BytesToRaw(buffer, MsgRec, SizeOf(TMsgRec));

  case MsgRec.Id of
    1: ClientAuth(MsgRec, AContext);
  end;

end;

procedure TMainForm.ClientAuth(MsgRec: TMsgRec; Client: TIdContext);
var
  i: Integer;
begin
  for i := 0 to concnt do begin   //Namenszuweisung für IP!
    if Connections[i].client.Binding.PeerIP = Client.Binding.PeerIP then begin
      Connections[i].name := MsgRec.auth.nickname;
      WriteProtocol('Client #' + IntToStr(concnt) + ': ' + Connections[i].client.Binding.PeerIP + ' changed Name to "' + Connections[i].name + '"');
    end;
  end;
  UpdateClientList;
end;

Klappt auch super :]

Muss jetzt nur noch einen Weg finden die Clients eindeutig zu identifizieren, auch wenn die IP dieselbe ist (das Anhängen der Identifizierungsinformationen an das Data Object scheint nicht zu klappen da der Client bei Indy 10 kein Data Objekt besitzt)

spaxxn 13. Jun 2008 08:30

Re: Records dynamisch verschachteln
 
Hmmm ich würde für den Zweck COM+/DCOM verwenden, aber wenns funtioniert, dann hau rein :D


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