Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Warum kann Record-Property nicht geschrieben werden? (https://www.delphipraxis.net/104453-warum-kann-record-property-nicht-geschrieben-werden.html)

Ares 4. Dez 2007 14:38


Warum kann Record-Property nicht geschrieben werden?
 
Hallo!

Folgender Aufbau:

Delphi-Quellcode:
type
  TMyData = record
    Data1: Boolean;
    Data2: String;
  end;

  TMyObject = class(TObject)
  protected
    FTest: Boolean;
    FData: TMyData;
  public
    property Test: Boolean read FTest write FTest;
    property Data: TMyData read FData write FData;
  end;

...
procedure Test;
var myObject: TMyObject;
begin
  myObject           := TMyObject.Create;
  myObject.Test      := true;
  myObject.Test      := options.Data.Data1;
  myObject.Data.Data1 := true;              //[Pascal Fehler] Der linken Seite kann nichts zugewiesen werden
end;
Bei der Anweisung myObject.Data.Data1 := true; kommt es wie beschrieben zu dem Fehler "Der linken Seite kann nichts zugewiesen werden". Ich verstehe nicht warum.

Die Property ist doch klar mit write als schreibbar markiert. Warum kann Data1 also nichts zuweisen? Mir ist dieses Problem mit Records vorher noch nie aufgefallen, allerdings habe ich auch noch nie auf diesen speziellen Fall geachtet...

Wie kann ich also Data.Data1 etwas zuweisen?

Besten Dank
Ares

Muetze1 4. Dez 2007 14:53

Re: Warum kann Record-Property nicht geschrieben werden?
 
Zitat:

Zitat von Ares
Bei der Anweisung myObject.Data.Data1 := true; kommt es wie beschrieben zu dem Fehler "Der linken Seite kann nichts zugewiesen werden". Ich verstehe nicht warum.

Die Property ist doch klar mit write als schreibbar markiert. Warum kann Data1 also nichts zuweisen? Mir ist dieses Problem mit Records vorher noch nie aufgefallen, allerdings habe ich auch noch nie auf diesen speziellen Fall geachtet...

Delphi geht logisch vor. Wenn du folgenden Konstrukt hast, dann geht Delphi logisch so vor:

myObject.Data.Data1 := true;

1. myObject ermitteln - habe ich
2. Eigenschaft Data ermitteln - also Getter aufrufen. Also bekomme ich als Result vom Getter eine Kopie des Records.
3. Diese Kopie lokal (vergleichbar mit einer lokalen Variablen ablegen).
4. Den Wert des Elementes Data1 aus dieser lokalen Variable verarbeiten.

Der Compiler weiss hierbei aber, dass es sich um eine lokale Variable handelt und markiert sie intern als konstant. Erstens weil es eine Kopie ist (der Getter hat den Record im Result und nicht als Pointer auf, somit eine Kopie). Und zum anderen kannst du keinen Teil zuweisen. Du hast einen Setter definiert für den Record - aber halt für den Record und nicht für das eine Element des Records. Was müsste Delphi machen um deine Anweisung umzusetzen?

1. Record holen (Kopie durch Getter)
2. die lokale Kopie abändern (also Data1 zuweisen)
3. die komplette Kopie durch den Setter wieder zuweisen.

Grundlegend: Was soll denn mit den anderen Elementen im Record geschehen wenn du nur ein Element zuweist, aber du immer nur einen Teil veränderst?

Anders gefragt: Wenn du dir ein Packet kommen lässt und darin ist eine Tasse und ein Teller. Der Postbote bringt dir das Packet und du willst aber nur die Tasse haben und den Rest wieder zurück schicken - bzw. du willst nur die Tasse annehmen. Da zeigt dir der Postbote auch einen Vogel. Entweder du nimmst das Packet ganz an und packst es aus und dann erneut neu ein und gibst es als ganzes (Packet) wieder bei der Post ab. Dann kannst du es aber nicht mehr unfrei zurück senden sondern musst erneut bezahlen.

Zitat:

Zitat von Ares
Wie kann ich also Data.Data1 etwas zuweisen?

Gar nicht. Auslesen kein Problem, aber zuweisen: Problem. Entweder eine nur-lesen Property und eine Methode als Setter oder definierst den Inhalt des Records als einzelne Properties.

Ares 4. Dez 2007 15:01

Re: Warum kann Record-Property nicht geschrieben werden?
 
Vielen Dank für den Hinweis.

Zitat:

Grundlegend: Was soll denn mit den anderen Elementen im Record geschehen wenn du nur ein Element zuweist, aber du immer nur einen Teil veränderst?
Natürlich nichts. Wenn ich auf LocalerRecord.Var1 zugreife wird ja auch nur Var1 verändert und nicht alle anderen Teile des Records.

Die Logik dahinter verstehe ich nicht ganz. Ein Record ist doch nur ein Konstrukt um mehrere Variablen zu einer logischen Einheit zusammen zu fassen. Warum der Zugriff auf die Teile also von Delphi nicht durchgereicht wird leuchtet mir nicht ein. Das ist aber auch egal, wichtig ist nur, dass es nicht geht :-) Ich werde mir also etwas anderes überlegen...

sirius 4. Dez 2007 15:05

Re: Warum kann Record-Property nicht geschrieben werden?
 
@Muetze: So richtig kann ich deine Erklärung nicht nachvollziehen.
Folgendes funktioniert ja:
1. aus dem Record eine Klasse machen
Delphi-Quellcode:
type
  TMyData = class
    Data1: Boolean;
    Data2: String;
  end;

  TMyObject = class(TObject)
  protected
    FTest: Boolean;
    FData: TMyData;
  public
    property Test: Boolean read FTest write FTest;
    property Data: TMyData read FData write FData;
  end;
  //und FData natürlich noch instanzieren (und am Ende wieder löschen)
2. ein dynmaischer Record:
Delphi-Quellcode:
type
  PMyData = ^TmyData
  TMyData = record
    Data1: Boolean;
    Data2: String;
  end;

  TMyObject = class(TObject)
  protected
    FTest: Boolean;
    FData: PMyData;
  public
    property Test: Boolean read FTest write FTest;
    property Data: PMyData read FData write FData;
  end;
  //und FData noch mit new(xxx) anlegen und mit dispose löschen

Jelly 4. Dez 2007 15:06

Re: Warum kann Record-Property nicht geschrieben werden?
 
Nutze doch einfach ebenfalls für dein Record eine eigene Klasse.

Kroko1999 4. Dez 2007 15:07

Re: Warum kann Record-Property nicht geschrieben werden?
 
ja, entweder so
type
Delphi-Quellcode:
 TMyData = record
    Data1: Boolean;
    Data2: String;
  end;

  TMyObject = class(TObject)
  protected
    FTest: Boolean;
    FData: TMyData;
  public
    property Test: Boolean read FTest write FTest;
    property Data: TMyData read FData write FData;
    property Data1: Boolean read FData.Data1 write FData.Data1; //etc.
  end;
oder so
Delphi-Quellcode:
procedure Test;
var
  myObject: TMyObject;
  MyData: TMyData;
begin
  myObject           := TMyObject.Create;
  myObject.Test      := true;
  myObject.Test      := options.Data.Data1;
MyData.Data1 := True;
  MyData.Data2 := 'Hurra';
  myObject.Data := MyData;
end;

Apollonius 4. Dez 2007 15:16

Re: Warum kann Record-Property nicht geschrieben werden?
 
@Ares: Wenn du als Setter ein Feld definierst, mag das ja noch einleuchten. Was soll der Compiler aber machen, wenn du eine Setter-Methode hättest? Die erwartet ja immer einen ganzen Record und nicht ein einzelnes Feld als Parameter.

Muetze1 4. Dez 2007 16:01

Re: Warum kann Record-Property nicht geschrieben werden?
 
Zitat:

Zitat von sirius
@Muetze: So richtig kann ich deine Erklärung nicht nachvollziehen.

Deshalb werde ich nie Tutorials schreiben: ich kann nicht erklären.

Zitat:

Zitat von sirius
Folgendes funktioniert ja:
1. aus dem Record eine Klasse machen

Du bekommst die Instanz und dadurch wird nur der Instanz dieser Wert zugewiesen. Es wird aber kein Setter aufgerufen. Und genau das ist das Problem bei dem Record. Dein Beispiel braucht auch kein Setter, da du mit dem Getter die Instanz bekommst und darauf kann er frei schalten und walten - Delphi hat also einen direkten Ansprechpartner zum setzen der letzten Ebene (Data1).

Der Setter ist in deinem Beispiel sogar gefährlich: Im Normalfall legt sich TMyObject die Instanz von TMyData an und hält diese die Lebzeit lang. Von daher wäre es mehr als tödlich wenn jemand dir von aussen direkt eine andere Instanz oder Nil unterschiebt. Von daher sind solche Properties generell eigentlich nur-lesen Eigenschaften. Und bei Komponenten etc. wird explizit ein Setter definiert um darin mit z.B. Assign() die Werte der Instanz zu übernehmen - aber niemals die Instanz!

Zitat:

Zitat von sirius
2. ein dynmaischer Record:

Wie ich oben schon geschrieben hatte: wenn es ein Pointer auf den Record ist, dann hat keiner ein Problem. Auch hier kann Delphi direkt die Werte setzen. Auch hier wird im Normalfall kein Setter gebraucht, es reicht eine r/o property.

Für beide gilt: in beiden Fällen bekommst Delphi einen Zeiger auf die Zieldaten und nicht direkt die Daten in die der Nutzer schreiben möchte. Von daher kann Delphi dies erledigen, da die temporäre Variable (result vom Getter) immer nur eine Adresse enthält, nicht aber die direkten Daten, wie es bei einem direkten Record (Ausgangsfall) ist.

sirius 4. Dez 2007 16:23

Re: Warum kann Record-Property nicht geschrieben werden?
 
Zitat:

Zitat von Muetze1
Zitat:

Zitat von sirius
@Muetze: So richtig kann ich deine Erklärung nicht nachvollziehen.

Deshalb werde ich nie Tutorials schreiben: ich kann nicht erklären.

:lol: sorry.

Aber jetzt habe ich es kapiert :mrgreen:


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