![]() |
Generic record
Ich möchte mit Hilfe von GENERICS beliebige Records in ein ByteArray und wieder zurück umwandeln .
Für die Lösung wollte ich zum ersten mal GENERICS in Delphi verwenden. Der Code unten spielt wenn ich anstelle von TGenericRecord eine beliebige Record Definition direkt einsetze. Habe ich einen Denkfehler in meinem Ansatz ?
Delphi-Quellcode:
type TGenericRecord <TRecordType> = class /// value : TRecordType; end; /// /// --------------- HELPER FUNCTION FOR RECORD EXCHANGE ------------------ /// function MyRecordToByteArray(aRecord: TGenericRecord): TBytes; var LSource: PAnsiChar; begin LSource := PAnsiChar(@aRecord); SetLength(Result, SizeOf(TGenericRecord)); Move(LSource[0], Result[0], SizeOf(TGenericRecord)); end; function ByteArrayToMyRecord(ABuffer: TBytes): TGenericRecord; var LDest: PAnsiChar; begin LDest := PAnsiChar(@Result); Move(ABuffer[0], LDest[0], SizeOf(TGenericRecord)); end; |
AW: Generic record
Dein genric Record ist eine generic Class :shock:
TGenericRecord<x> entspricht nicht TGenericRecord
Delphi-Quellcode:
, da aber keine generischen Prozeduren möglich sind, muß dieses eine Methode eines Records oder eines Objekts werden.
function MyRecordToByteArray<X>(aRecord: TGenericRecord<x>): TBytes;
statt Zitat:
Zitat:
Zitat:
|
AW: Generic record
Ich glaub, du möchtest so etwas:
Delphi-Quellcode:
Denke aber bei diesem Ansatz auf jeden Fall daran, dass du damit keine managed types (z.B. string) behandeln kannst. Denn in dem Record befindet sich in diesem Fall nur ein Pointer auf den string.
type
TRecordSerializer = class class function ToByteArray<T: record>(const Value: T): TBytes; static; class function ToRecord<T: record>(const Value: TBytes): T; static; end; class function TRecordSerializer.ToByteArray<T>(const Value: T): TBytes; begin SetLength(Result, SizeOf(T)); Move(Value, Result[0], SizeOf(T)); end; class function TRecordSerializer.ToRecord<T>(const Value: TBytes): T; begin Move(Value[0], Result, SizeOf(T)); end; |
AW: Generic record
@ Stevie : in meinen records können leider auch Strings vorkommen .... kann damit Deine Lösung nicht verwenden
@ Himitsu : wenn ich keine Generic Typs als Funktions Rückgabewert verwenden kann --> dann muss ich wohl auf das gute & alte function overloading zurückgreifen :oops:; im Code unten maul der Compiler "TRecordType" kennt er nicht, ist doch klar.... kenne ich gerade selbst noch nicht .... sage ich dem Compiler schon und zwar dann wenn ich die Funktion auch verwenden will .... mit TGenericRecord<TAnwerndungsrecord>.Create, solange soll er halt warten
Delphi-Quellcode:
function MyRecordToByteArray(aRecord: TGenericRecord<TRecordType>): TBytes; var LSource: PAnsiChar; begin LSource := PAnsiChar(@aRecord); SetLength(Result, SizeOf(TMyRecord)); Move(LSource[0], Result[0], SizeOf(TGenericRecord<TRecordType>)); end; function ByteArrayToMyRecord(ABuffer: TBytes): TGenericRecord<TRecordType>; var LDest: PAnsiChar; begin LDest := PAnsiChar(@Result); Move(ABuffer[0], LDest[0], SizeOf(TGenericRecord<TRecordType>)); end; |
AW: Generic record
Zurückgeben kann man es, aber
Delphi-Quellcode:
ist nicht möglich ... das geht leider nur bei Methoden (Record oder Object).
function MyFunction<T>(...): ...;
|
AW: Generic record
was Delphi auf nicht compiliert :-(
Delphi-Quellcode:
type TRecordTypeA= .... .... ... .. // gib mir ein record type 1 zurück function testfunction (a : Integer) : TRecordTypeA; overload; // nun type 2 function testfunction (a : Integer) : TRecordTypeB; overload; // usw .... function testfunction (a : Integer) : TRecordTypeC; overload; müsste ich etwas wie
Delphi-Quellcode:
codieren.procedure (a : Integer; var TGenericRecordType<T> ); bzw. Zitat:
TGenericTRecord <TRecordtype>= class function ByteArrayToMyRecord(ABuffer: TBytes): TRecordtype end; |
AW: Generic record
Natürlich nicht.
Beim Überladen muß sich die Aufrufsignatur unterscheifen, also die Parameter müssen unterschiedlich sein. Bei dir sind sie aber gleich. Zitat:
Delphi-Quellcode:
// geht
TGenericTRecord<TRecordtype> = class function ByteArrayToMyRecord(ABuffer: TBytes): TRecordtype; class function ByteArrayToMyRecord(ABuffer: TBytes): TRecordtype; static; end; // geht TGenericTRecord = class function ByteArrayToMyRecord<TRecordtype>(ABuffer: TBytes): TRecordtype; class function ByteArrayToMyRecord<TRecordtype>(ABuffer: TBytes): TRecordtype; static; end; // geht nicht function ByteArrayToMyRecord<TRecordtype>(ABuffer: TBytes): TRecordtype; |
AW: Generic record
Zitat:
|
AW: Generic record
schau mal hier rein vllt bringt dich das weiter
![]() |
AW: Generic record
@himitsu :
warum benötige ich Zitat:
Delphi-Quellcode:
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TMyRecordA = record Details: string[255]; FileName: string[255]; FileDate: TDateTime; FileSize: Integer; Recordsize: Integer; end; TMyRecordB = record Details: string[255]; x: Real; y: Real; z: Real; end; TMyRecordC = record FileDate: TDateTime; FileSize: Integer; x: Real; y: Real; z: Real; end; TGenericRecord<TRecordType> = class value : TRecordType ; /// <summary> /// Convert Byte to Record , outputtype : TRecordType /// </summary> /// <param name="ABuffer"> /// Byte Array /// </param> function ByteArrayToMyRecord(ABuffer: TBytes): TRecordType; // class function ByteArrayToMyRecord(ABuffer: TBytes): TRecordType; static; /// <summary> /// Store a Record into a BYTE Array /// </summary> /// <param name="aRecord"> /// adjust this record definition to your needs /// </param> function MyRecordToByteArray(aRecord: TRecordType): TBytes; // class function MyRecordToByteArray(aRecord: TRecordType): TBytes; static; end; var Form1: TForm1; implementation {$R *.dfm} function TGenericRecord<TRecordType>.MyRecordToByteArray(aRecord: TRecordType): TBytes; var LSource: PAnsiChar; begin LSource := PAnsiChar(@aRecord); SetLength(Result, SizeOf(TRecordType)); Move(LSource[0], Result[0], SizeOf(TRecordType)); end; function TGenericRecord<TRecordType>.ByteArrayToMyRecord(ABuffer: TBytes): TRecordType; var LDest: PAnsiChar; begin LDest := PAnsiChar(@Result); Move(ABuffer[0], LDest[0], SizeOf(TRecordType)); end ; procedure TForm1.Button1Click(Sender: TObject); var a_record : TGenericRecord<TMyRecordA>; b_record : TGenericRecord<TMyRecordB>; c_record : TGenericRecord<TMyRecordC>; ABuffer : TBytes; begin /// create class a_record :=TGenericRecord<TMyRecordA>.Create; b_record :=TGenericRecord<TMyRecordB>.Create; c_record :=TGenericRecord<TMyRecordC>.Create; /// einb paar werte zuweisen ..... a_record.value.Details := '#1 bla bla'; a_record.value.FileName := '#2 bla bla'; a_record.value.Recordsize := 100; a_record.value.FileSize := 222; b_record.value.x := 1; b_record.value.y := 2; b_record.value.z := 3; /// im buffer daten zwischenlagern ABuffer := a_record.MyRecordToByteArray(a_record.value); /// löschen oder mit anderen daten arbeiten a_record.value.Details := '.....'; a_record.value.FileName := '----'; a_record.value.Recordsize := -1; a_record.value.FileSize := -2; // Daten wieder aus dem Buffer zurücklesen a_record.value := a_record.ByteArrayToMyRecord(ABuffer); /// alte daten sind wieder da :-) memo1.lines.add( a_record.value.Details) ; memo1.lines.add( a_record.value.Filename) ; /// free class a_record.Free; b_record.Free; c_record.Free; end; end |
AW: Generic record
Da du in deinen records shortstrings (string[n]) benutzt, geht die von mir vorgeschlagene Lösung sehr wohl.
Hat auch den Vorteil, dass du keinen extra Datentyp (die Wrapperklasse für den Record) brauchst:
Delphi-Quellcode:
var
a_record : TMyRecordA; b_record : TMyRecordB; c_record : TMyRecordC; ABuffer : TBytes; begin // ein paar werte zuweisen ..... a_record.Details := '#1 bla bla'; a_record.FileName := '#2 bla bla'; a_record.Recordsize := 100; a_record.FileSize := 222; b_record.x := 1; b_record.y := 2; b_record.z := 3; // im buffer daten zwischenlagern ABuffer := TRecordSerializer.ToByteArray<TMyRecordA>(a_record); // du kannst in diesem Fall das <TMyRecordA> auch weglassen, // da der Compiler das durch den Typen des übergebenen Parameter erkennt // Stichwort Type Inference // löschen oder mit anderen daten arbeiten a_record.Details := '.....'; a_record.FileName := '----'; a_record.Recordsize := -1; a_record.FileSize := -2; // Daten wieder aus dem Buffer zurücklesen a_record := TRecordSerializer.ToRecord<TMyRecordA>(ABuffer); // alte daten sind wieder da :-) memo1.lines.add( a_record.Details); memo1.lines.add( a_record.Filename); end; |
AW: Generic record
Liste der Anhänge anzeigen (Anzahl: 1)
Delphi-Quellcode:
Eine Konsolenanwendung ist beigefügt.
type
{ Generika sind nicht nötig: } TMeinRecord = record Value: TBeliebigerFeldtyp; // mehr beliebige Feldtypen class operator Implicit(const Value: TMeinRecord): TBytes; class operator Implicit(const Value: TBytes): TMeinRecord; end; class operator TMeinRecord.Implicit(const Value: TMeinRecord): TBytes; var Size: NativeInt; begin Size := SizeOf(Value); SetLength(Result, Size); // if Size > 0 then Move(Value, Result[0], Size); end; class operator TMeinRecord.Implicit(const Value: TBytes): TMeinRecord; var Size: NativeInt; begin Size := Length(Value) { entspricht Größe in Bytes }; if Size <> SizeOf(Result) then raise Exception.Create('Ungültige Feldgröße'); Move(Value[0], Result, Size); end; |
AW: Generic record
Zitat:
|
AW: Generic record
Ja, stimmt,
Delphi-Quellcode:
arbeitet mit keinem (und deshalb mit jedem) (Feld-) Datentyp. Im angehängten Quelltext ist das auch bemerkt. Ich wollte nicht fragen, wofür man das braucht, obwohl ich diese Frage wirklich im Kopf habe. (Bitte keine Antworten.) Stattdessen habe ich mich entschieden, etwas vorzuschlagen.
Move
Wenn man es auf Feldtypen allgemein ausrichten will:
Delphi-Quellcode:
Irgendwie sind alle Aufrufe schon ziemlich nah am
type
Fieldtype = record class function ToBytes(const Value; const Size: NativeInt): TBytes; overload; static; class function ToBytes<T>(const Value: T): TBytes; overload; static; class function FromBuffer<T>(const Value; const Size: NativeInt): T; static; class function FromBytes<T>(const Value: TBytes): T; static; end;
Delphi-Quellcode:
...
Move
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:34 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