![]() |
Record Property verschachtelt - Schreibzugriff
Hallo,
mir ist vorhin aufgefallen, dass man bei verschachtelten Records keine Werte zuweisen kann. Warum ist das so oder hab ich da irgendwie einen Denkfehler?
Delphi-Quellcode:
Mache ich aus TTestRec2 eine Klasse oder wenn ich statt auf die Property Test2 direkt auf FTest2 zugreife, funktioniert es.
TTestRec1 = record
public IntValue: Integer; end; TTestRec2 = record // <- Wenn man das Record als Klasse deklariert funktioniert es public Test1: TTestRec1; end; TTestObj1 = class( TObject) private FTest2: TTestRec2; public property Test2 : TTestRec2 read FTest2 write FTest2; end; ... procedure TForm53.FormCreate(Sender: TObject); var ltest: TTestObj1; begin ltest := TTestObj1.Create; ltest.Test2.Test1.IntValue := 10; // <- "Der linken Seite kann nichts zugewiesen werden" ltest.FTest2.Test1.IntValue := 10; // <- Funktioniert end; Aber warum kann man da nichts eintragen wenn man die Property nutzt? |
AW: Record Property verschachtelt - Schreibzugriff
Ich hab gerade bemerkt das es ja auch schon direkt bei der ersten Ebene nicht funktioniert.
Aber hab da noch eine andere Möglichkeit gefunden.
Delphi-Quellcode:
Mir ist nur nicht ganz klar wieso das nicht funktioniert ein Record als Property zu verwenden und die einzelnen Eigenschaften des Records zuzuweisen.
TTestRec1 = record
public IntValue: Integer; end; TTestObj1 = class( TObject) private FTest1: TTestRec1; public property Test1 : TTestRec1 read FTest1 write FTest1; property Test1IntValue : Integer read FTest1.IntValue write FTest1.IntValue; // <- So funktioniert es auch [1/2] end; ... procedure TForm53.FormCreate(Sender: TObject); var ltest: TTestObj1; begin ltest := TTestObj1.Create; ltest.Test1.IntValue := 10; // <- "Der linken Seite kann nichts zugewiesen werden" ltest.Test1IntValue := 10; // <- So funktioniert es auch [2/2] end; |
AW: Record Property verschachtelt - Schreibzugriff
Wenn du ein Record als Property hast, dann greifst du beim Schreiben auf die Record-Felder ja auf den Getter des Properties zu. Dieser gibt dir aber eine Kopie des Records zurück und nicht das Record-Feld in der Klasse. Du änderst dann eben auch nie diese Kopie und nicht das Original.
Bedenke mal den Fall, wo der Getter eine Funktion ist, die den Record dynamisch zusammensetzt. Wo sollten dann deine Änderungen landen? |
AW: Record Property verschachtelt - Schreibzugriff
Solange die Properties direkt auf die Felder zugreifen, hatte ich eigentlich gedacht, dass es funktioniert. Das mag allerdings bei verschiedenen Delphi-Versionen unterschiedlich sein.
ABER: Sobald Getter und Setter Methoden involviert sind, geht das spätestens zur Laufzeit schief, auch wenn es compiliert. Der Gettter liefert immer eine Kopie des Records zurück. Du änderst dann die Properties der Kopie und das Original bleibt unverändert. Dasselbe gilt auch beim Aufruf von Methoden, die den Record verändern: Sie ändern die Kopie. Edit: Uwe war schneller. |
AW: Record Property verschachtelt - Schreibzugriff
Nein, es gibt immer eine Kopie und selbst wenn nicht, dann wäre es ein gefährlich/zufälliges Verhalten .. mit Getter oder nicht, mal Kopie oder nicht.
Man kann hier mit Klassen arbeiten oder mit Properties im Record *1 1) im Record eine Referenz auf das Original und im Setter des Record-Property dann nicht nur im Record, sondern auch im Original ändern. Toll wäre es, wenn Emba mal auf seine kunden hören und nicht zuviele Feature-/Bugreports sinnlos schließen würde. Bei einem Schreibzugriff auf ein Property muß am Ende einfach nur nochmal der Setter aufgerufen werden.
Delphi-Quellcode:
X.MeinProperty.xxx := irgendwas
// wird ja als kompiliert Temp := X.GetMeinProperty; Temp.xxx := irgendwas // und am Ende fehlt einfach nur noch eine implizite Zeile, nach dem Schreibzugriff X.SetMeinProperty(Temp); |
AW: Record Property verschachtelt - Schreibzugriff
Geht auch mehrfach verschachtelt:
Delphi-Quellcode:
:cool:
TTestObj1 = class( TObject)
private FTest2: TTestRec2; public property IntValue: Integer read FTest2.Test1.IntValue write FTest2.Test1.IntValue; end; ... var ltest: TTestObj1; begin ltest := TTestObj1.Create; ltest.IntValue := 10; end; Zum Problem an sich haben die anderen ja schon was gesagt - der Kern ist hier die API - die definiert hier eine Eigenschaft eines Wertetypens, und auch wenn der Zugriff auf ein Feld ohne Getter durch den Compiler letztlich im Binärcode als direkter Speicherzugriff implementiert wird und es auch einige Schlupflöcher(*) gibt, wird hier sichergestellt, dass man durch das direkte Zuweisen des Feldes auf das, was eine Kopie sein könnte nicht passiert. (*) 1. Durch das Hinzufügen von Methoden zu Recordtypen wurde das ganze ein bisschen kompliziert gemacht - Beispiel:
Delphi-Quellcode:
2. Wenn Eigenschaften direkt auf ein Feld gehen, kann man mit @ auf die Addresse "durchgreifen":
type
TTestRec = record public IntValue: Integer; procedure SetValue(i: Integer); end; TTestObj = class private FTest: TTestRec; function GetTest2: TTestRec; public property Test: TTestRec read FTest; property Test2: TTestRec read GetTest2; end; procedure TTestRec.SetValue(i: Integer); begin IntValue := i; end; function TTestObj.GetTest2: TTestRec; begin Result := FTest; end; procedure Test; var t: TTestObj; begin t := TTestObj.Create; t.Test.SetValue(10); t.Test2.SetValue(20); Writeln(t.Test.IntValue); // was kommt raus? Spoiler: 10 end;
Delphi-Quellcode:
procedure SetValue(val: PInteger; i: Integer);
begin val^ := i; end; ... procedure Test; var t: TTestObj; begin t := TTestObj.Create; SetValue(@t.Test.IntValue, 30); // funktioniert SetValue(@t.Test2.IntValue, 40); // funktioniert nicht - compilefehler E2036 Variable required end; |
AW: Record Property verschachtelt - Schreibzugriff
und als Ergänzung, wenn Du mit Klassen statt Records arbeitest: Verwende Interfaces, damit Du Dich nicht mehr um das Release kümmern musst (zB beim Zuweisen eines neuen Objekts an das Property).
|
AW: Record Property verschachtelt - Schreibzugriff
:thumb: Vielen Dank für die ausführlichen Erklärungen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:41 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