![]() |
array of const für spätere Verwendung speichern
Hallo zusammen,
ich kämpfe hier gerade mit einem Problem. Ich habe eine Methode geschrieben, welche als Parameter "array of const" beinhaltet. Dieses "array of const" soll zu einem späteren Zeitpunkt an die "Format"-Funkion übergeben werden. "array of const" ist ja bekanntermaßen ein "array of TVarRec". Also habe ich das auch so deklariert (Strukturen und Code für bessere Übersichtlichkeit gekürzt):
Delphi-Quellcode:
In meiner Methode werden die Werte dann mit folgendem Code zwischengespeichert:
PRec = ^TRec;
TRec = record Params: array of TVarRec; end;
Delphi-Quellcode:
Soweit so gut. Der generierte Record wird einer Thread-Liste abgelegt und dann von einer anderen Thread verarbeitet. Das funktioniert auch alles bestens, solange ich Strings oder Konstante Werte in "Args" übergebe. Übergebe ich aber z.B. eine numerische Variable, so ist diese nur verfügbar, solange ich in der Methode "Something" bin. Beim Verlassen der Methode wird diese finalisiert und löst dann natürlich eine Exception aus, sobald auf diese zugegriffen wird. Ich habe das getestet indem ich in der Methode geblieben bin, bis die Thread die Parameter verarbeitet hatte...
procedure Something(const Args: array of const);
var RecPtr: PRec; begin New(RecPtr); SetLength(RecPtr^.Params, Length(Args)); for I := Low(Args) to High(Args) do RecPtr^.Params[I] := Args[I]; end; Zum weiteren Verständnis: Die Thread holt die Records nacheinander vom Puffer (TThreadList) und verarbeitet diese asynchron zum aufrufenden Programm. Leider können die Args erst dort verarbeitet werden, da die endgültigen Formatstrings erst in der Thread verfügbar sind... Mir fällt leider im Moment keine elegante Lösung ein. Irgendwie müsste ich mich da manuell um "Initialize" und "Finalize" kümmern. Hat jemand von euch eine Idee? Ich hoffe das Problem ist einigermaßen verständlich geschildert und ich habe mich beim "Pseudo"-Code nicht zu sehr vertippt :-). PS: Eine Lösung wäre bei bestimmten Typen (z.B. VExtended) die als Pointer gespeichert werden diese mit New(RecPtr^.Params[I].VExtended) dynamisch zu allokieren und den Wert mit RecPtr^.Params[I].VExtended^ := Args[I].VExtended^ zu übernehmen. Später müsste dann dieser mit Dispose(RecPtr^.Params[I].VExtended) dann wieder freiegeben werden. Ist aber sehr umständlich und man müsste die richtigen Typen ermitteln und das bei allen (auch zukünftigen) Typen korrekt durchführen. Ist nicht sehr elegant. Freue mich über alle Antworten! Alex |
AW: array of const für spätere Verwendung speichern
Kannst du einen minimalen Testfall bereitstellen?
|
AW: array of const für spätere Verwendung speichern
Was sind "nummerische Werte"?
Delphi-Quellcode:
Alles größer als Integer wird per Pointer referenziert und lebt nur so lange, wie es der aufrufende Code bereitstellt.
TVarRec = record { do not pack this record; it is compiler-generated }
case Integer of 0: (case Byte of vtInteger: (VInteger: Integer); vtExtended: (VExtended: PExtended); vtString: (VString: PShortString); vtAnsiString: (VAnsiString: Pointer); vtCurrency: (VCurrency: PCurrency); vtVariant: (VVariant: PVariant); vtWideString: (VWideString: Pointer); vtInt64: (VInt64: PInt64); vtUnicodeString: (VUnicodeString: Pointer); Strings sind referenzgezählt und in diesem Array wird die Referenz nicht mitgezählt (CONST) ... geht der Referenzzähler auf 0, so ist der String weg. Fazit: Du mußt selber einen Speicherplatz bereitstellen und die Inhalte umkopieren, wenn sie nicht im aktuellen Programmpfad behandelt werden. z.B. ein paar Array of AnsiString/UnicodeString/Int64/Extended/Variant, auf deren Speicher dann deine TVarRec zeigen. (alternativ nur Array of Variant und alles nach Variant konvertieren) New/Dispose wären auch möglich, aber so mußt du dich nicht um das (interne) Speichermanagement kümmern. |
AW: array of const für spätere Verwendung speichern
Ich würde das mal mit
Delphi-Quellcode:
versuchen. Der löst in
TValue
Delphi-Quellcode:
die Referenzen auf die Pointer auf. Die Zuweisung kann in dem Fall sogar wegen
FromVarRec
Delphi-Quellcode:
so bleiben. Lediglich bei der Auswertung muss man dann halt was machen (z.B. über
Implicit
Delphi-Quellcode:
).
AsVarRec
Delphi-Quellcode:
PRec = ^TRec;
TRec = record Params: array of TValue; end;
Delphi-Quellcode:
procedure Something(const Args: array of const);
var RecPtr: PRec; begin New(RecPtr); SetLength(RecPtr^.Params, Length(Args)); for I := Low(Args) to High(Args) do RecPtr^.Params[I] := Args[I]; end; |
AW: array of const für spätere Verwendung speichern
TValue: Dieses Array kann man aber nicht an ein
Delphi-Quellcode:
übergeben?
array of const
Delphi-Quellcode:
PS: Bei Record-Pointer kann man die Dereferenzierung weg lassen, wenn man auf Felder/Property/Funktionen zugreift, da Delphi das impliziet macht. Halt wie bei den Objekten, nur dass dort die explizite Angabe nicht erlaubt ist. :stupid:
procedure Something(const Args: array of const);
var RecPtr: PRec; begin New(RecPtr); SetLength(RecPtr.Params, Length(Args)); for I := Low(Args) to High(Args) do RecPtr.Params[I] := Args[I]; // Format('', RecPtr.Params); Dispose(RecPtr); end; Aber so lässt sich der Code später mal problemloser auf schöne Datenobjekte umstellen. |
AW: array of const für spätere Verwendung speichern
Zitat:
Delphi-Quellcode:
aufbauen:
array of TVarRec
Delphi-Quellcode:
type
TRec = record private function GetAsVarRecs: TArray<TVarRec>; public Params: array of TValue; constructor Create(const AParams: array of const); property AsVarRecs: TArray<TVarRec> read GetAsVarRecs; end; constructor TRec.Create(const AParams: array of const); var I: Integer; begin SetLength(Params, Length(AParams)); for I := Low(AParams) to High(AParams) do begin Params[I] := AParams[I]; end; end; function TRec.GetAsVarRecs: TArray<TVarRec>; var I: Integer; begin SetLength(result, Length(Params)); for I := Low(Params) to High(Params) do begin result[I] := Params[I].AsVarRec; end; end; procedure Test(const Fmt: string; const Args: array of const); var rec: TRec; S: string; begin rec := TRec.Create(Args); S := Format(Fmt, rec.AsVarRecs); Assert(S = Format(Fmt, Args)); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:52 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