![]() |
Record als Konstantenobjekt nach Update D2009->Delphi XE
Schönenn guten Abend,
ich habe gerade ein Update von Delphi 2009 auf Delphi XE durchgeführt. Beim Start eines Projektes, durfte ich feststellen, daß eine alte Unit nicht mehr funktioniert. Mir ist derzeit nicht ganz klar, wo der Fehler liegt. Vielleicht kann mir hier jemand einen Tipp geben. Ich bekomme die Fehlermeldung, daß ich hier ein jetzt Konstantenobjekt habe und als Folgefehler daraus die Meldung, daß nichts zugewiesen werden kann. Möglicherweise liegt es an einigen Veränderungen zwischen D2009->DXE. Ich hoffe ich habe hier alle relevanten Teile für eine Beispielprozedur rauskopiert.
Delphi-Quellcode:
Analog gibt es noch andere Stellen, wo der Fehler meiner Meinung nach aber die selbe Ursache haben dürfte. Bisher habe ich mit dieser Unit nie Probleme gehabt. Ich schleppe sie seit D7 in einem Projekt mit durch. Möglicherweise bin ich gerade mit Blindheit geschlagen, aber ich komm nicht drauf.
unit uFLPReader;
interface uses Windows, Classes, SysUtils; type TAlgenklassenparameter = packed record _Name: AnsiString; _FlagUseInFit: Longint; _Fingerprint_Standardabweichung: array[1..16] of Double; _LEDOffset: Double; end; TParametersOfFit1 = packed record _Algenklassenparameter: array[1..8] of TAlgenklassenparameter; end; TFLPModule = class(TObject) private FParametersOfFit1: TParametersOfFit1; procedure ReadParametersOfFit1(const AStream: TStream); public property ParametersOfFit1: TParametersOfFit1 read FParametersOfFit1; end; implementation procedure TFLPModule.ReadParametersOfFit1( const AStream: TStream); var i : Integer; NameLen : Longint; Dummy : AnsiString; begin for i := 1 to 8 do with ParametersOfFit1._Algenklassenparameter[i] do begin AStream.ReadBuffer(NameLen, SizeOf(NameLen)); SetLength (_Name, NameLen); // hier ein Fehler if NameLen > 0 then Begin AStream.ReadBuffer(_Name[1], NameLen); // hier ein Fehler _Name := Copy (_Name, 0, NameLen-1); end Else Begin _Name := ''; end; AStream.ReadBuffer(_FlagUseInFit, SizeOf(_FlagUseInFit)); // hier ein Fehler AStream.ReadBuffer(_Fingerprint_Standardabweichung, SizeOf(_Fingerprint_Standardabweichung)); // hier ein Fehler AStream.ReadBuffer(_LEDOffset, SizeOf(_LEDOffset)); // hier ein Fehler end; end; Herzlichen Dank, Jan |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Mal mit ohne with versucht?
|
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
ParametersOfFit1 ist als property nur "read" deklariert, FParametersOfFit1 verwenden.
|
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
In 2010/XE gab es ein paar Änderungen bezüglich der Zugriffsprüfungen von Const-Parametern und anderen Konstanten.
Kann schon sein, daß sich da ein Bug versteckt hat. PS:
Delphi-Quellcode:
... 0?
Copy (_Name, 0, NameLen-1);
Zitat:
und der Code hätte nie funktionieren dürfen, da man die Inhalte von Record-Parametern nicht ändern kann, es sei denn man weist einen kompletten Record zu. Änderungen an einzelnen Feldern werden nur an der Kopie des Property vorgenommen und nicht an dem, worauf das Property zeigt ... darum diese Meldung. [edit] durch die Codeoptimierung funktionierte es zufällig doch mal Du mußt dort auf FParametersOfFit1 zugreifen. :warn: |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Zitat:
Zitat:
Report No: 56893 (RAID: 257191) Status: Closed with <> ".": Syntax ambiguity?! ![]() Zitat:
Delphi-Quellcode:
with t.Items[0] do
begin writeln(s); // str s := ':('; b := true; writeln(b); // true end; writeln(t.Items[0].s); // str <-- data loss writeln(t.Items[0].b); // false <-- data loss |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Sobald lesend auf ein Property zugegriffen wird (also nicht Property := ...), wird READ verwendet, welches eine lokale Kopie des Wertes erstellt.
Alles was in dieser Kopie verändert wird, hat keinen Einfluß auf das Property. [add] (bei direkten Zugriffen auf Felder ht es doch Einfluß, was aber so nicht erlaubt ist) Darum wirft man hier nun auch endlich mal einen Compiler-Fehler. Was aber leider auf Record-Methoden noch nicht zutrifft, da man diese nicht als "Konstant" deklarieren kann. Ist schon witzig, wie man darüben dennoch eine Konstante verändern kann. :roll: Dieser Code
Delphi-Quellcode:
macht nun Folgendes:
with t.Item do
begin s := ':('; writeln(s); // str b := true; writeln(b); // true end; writeln(t.Item.s); // str <-- data loss writeln(t.Item.b); // false <-- data loss t.Item.s := ':)'; writeln(t.Item.s); // str <-- data loss
Delphi-Quellcode:
(die Codeoptimierung ist natürlich so schlau möglichst nur eine Temp-Variable zu nutzen und diese überall wiederzuverwenden, was aber an den auszuführenden Befehlen nichts ändert)
Temp1 := t.Item; // t.Item {Getter}
begin Temp1.s := ':('; writeln(Temp1.s); Temp1.b := true; writeln(Temp1.b); end; Temp2 := t.Item; writeln(Temp2.s); Temp3 := t.Item; writeln(Temp3.b); Temp4 := t.Item; Temp4.s := ':)'; Temp5 := t.Item; writeln(Temp5.s); Da Emba ja leider nicht von selber auf die Idee kommt, hier nachher die TempVar an den Setter zurück zu übergeben, muß man es manuell machen.
Delphi-Quellcode:
MyVar := t.Item; {Getter}
with MyVar do begin s := ':('; writeln(s); b := true; writeln(b); end; t.Item := MyVar; {Setter} writeln(t.Item.s); {Getter} writeln(t.Item.b); {Getter} MyVar := t.Item; {Getter} MyVar.s := ':)'; t.Item := MyVar; {Setter} writeln(t.Item.s); {Getter} PS: Das trifft auch auf Objekte zu, genauer auf den Objektzeiger. Den Objektinhalt kann man natürlich ändern, da er ja nicht in dieser Kopie enthalten ist. :angle2: PSS: Das selbe Problem hat übrigens auch die generische TList. :wall: (vielleicht lade ich dazu ja irgendwannl meinen "Bugfix" hoch) |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Zitat:
Delphi-Quellcode:
Der Code beim ShowMessage ist identisch mit:
TMyClass=class(TObject)
private fMyRecord: TMyRecord; public property MyRecord: TMyRecord read fMyRecord; end; [...] ShowMessage(MyClassInstance.MyRecord.Value);
Delphi-Quellcode:
Wäre ja schlimm der Zugriff auf eine Variable Länger dauert nur weil man den Scope oder dergleichen einschränkt.
TMyClass=class(TObject)
public MyRecord: TMyRecord; end; [...] ShowMessage(MyClassInstance.MyRecord.Value); |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
hmmmmm.
OK, wenn, dann aber nur, wenn direkt auf auf ein Feld zugegriffen wird. Gut, so könnte es doch mal zufällig funktioniert haben. ( Codeoptimierung? ) Da aber theoretisch auch ein Getter möglich wäre, würde/dürfte es dennoch nicht gehn. PS: Das ist/war natürlich auch ein "Sicherheitsloch", da es ja als "schreibgeschützt" deklariert war. :angle: |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Natürlich funktioniert das nur wenn auf ein Feld zugegriffen wird. Aber genau darum ging es hier.
Wenn man eine Funktion hat die etwas zurück liefert sollte klar sein das mit Änderung des Funktionsergebnisses nicht das geändert wird woraus das Funktionsergebnis zusammengesetzt wird. Dafür würde ja auch die Verknüpfung fehlen:
Delphi-Quellcode:
Hier sollte klar sein das folgendes nicht geht da die Verknüpfung von TMyREcord.Val mit fVal1 fehlt.
TMyObject = class(TObject)
private fVal1: Integer; fVal2: Integer; function GetValues(): TMyRecord; public property MyRecord: TMyRecord read GetValues; end; [...] function TMyObject.GetValues(): TMyRecord; begin result.Val1:=fVal1; result.Val2:=fVal2; end;
Delphi-Quellcode:
MyObjectInstance.MyRecord.Val1:=Irgendwas;
Zitat:
Read und Write sind Schlüsselwörter um den Zugriff zu begrenzen ebenso wie private,protected etc. [Edit] Diese Schlüsselwörter dienen nicht dazu den Speicher zu verschlüsseln oder andere Stolpersteine zu erzeugen um zu verhindern das man den Speicher nutzen kann. Sie dienen einzig und allein dem Begrenzen des "normalen" Zugriffs über Properties etc. |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
"zufällig" im sinne von, daß hier zufällig kein Getter verwendet wurde.
Wäre ja großer Zufall, wenn hier damals wirklich so geplant wurde, daß diese Codeoptimierung ausgenutzt werden konnte. :angle2: |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Von mir aus darf das auch gern weiterhin so bleiben. So kommt man wenigstens auch (schreibend) an Variablen ran die beim Design der VCL-Klassen im Private-Teil gelandet sind aber besser im Protected-Teil aufgehoben wären.
|
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Sagen wir es mal so ... man kommt immernoch an solche Variablen ran, denn diesen Zugriffsschutz kann man umgehen (zum Glück kennt Delphi das @),
dann gibt es noch die neue RTTI, welche solch Privaten auch mit auflistet und man kann sich auch auf andere Wege durch brutalstes Rumgepointere an die geheimsten Dinge ranschleichen. :twisted: |
AW: Record als Konstantenobjekt nach Update D2009->Delphi XE
Sorry,
neuer Job, in Kürze zweites Kind, umgezogen -> ergo, in der noch internetfreien Umzugsbaustelle eingespannt gewesen... Deshalb erst jetzt eine Antwort; hab aber gestern Abend auf meinem kleinen Androiden schon mal mitgelesen. Irgendwie war ich wohl tatsächlich mit Blindheit geschlagen. Das hier der Setter fehlt ist mir tatsächlich komplett entgangen. Ich habe (da der Source funktionierte) den Fehler natürlich woanders gesucht. Die Geschichte mit With, etc. waren natürlich die ersten Schritte bevor ich hier gepostet habe. Wenn man direkt FParametersOfFit1 im With Konstrukt verwendet compiliert der Source problemfrei durch und Testdatenfiles werden wieder korrekt importiert. Ein
Delphi-Quellcode:
auf
Write
Delphi-Quellcode:
bei der
FParametersOfFit1
Delphi-Quellcode:
langt hingegen nicht. Das muss ich mir wohl noch mal anschauen; da bin ich noch nicht ganz klar mit. Gibt es hier evtl. Neuerungen bezüglich der
Property ParametersOfFit1
Delphi-Quellcode:
?
packed records
Viel spannender finde ich aber die Tatsache, das dies vorher wirklich funktioniert hat. Absichtlich wurde dies nicht so gecoded. Es funktioniert, war in Stresstests mit korrupten Daten-Files robust und belastbar und lief recht schnell. Also hab ich den Code in neuen Updates natürlich immer weiter verwendet, bis ich vor 4-5 Jahren das Projekt erst mal halb auf Eis gelegt habe und nur noch private Builds compiliert habe. Jetzt bin ich gerade dabei es wieder auszugraben und noch einmal komplett zu überarbeiten, damit man eine zeitgemäßere Version hat, mit der man sich auch mal unter Kollegen trauen kann. Softwareentwicklung ist eigentlich nicht mein Hauptgebiet... Herzlichen Dank Jan Sc+*+.# Restfehlerrate... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:33 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