“Left side cannot be assigned to” for record type properties in Delphi

前端 未结 8 949
夕颜
夕颜 2020-12-01 16:09

I\'m curious to know why Delphi treats record type properties as read only:

  TRec = record
    A : integer;
    B : string;
  end;

  TForm1 = class(TForm)
         


        
相关标签:
8条回答
  • 2020-12-01 16:52

    Like others have said - the read property will return a copy of the record, so the assignment of fields isn't acting on the copy owned by TForm1.

    Another option is something like:

      TRec = record
        A : integer;
        B : string;
      end;
      PRec = ^TRec;
    
      TForm1 = class(TForm)
      private
        FRec : PRec;
      public
        constructor Create;
        destructor Destroy; override;
    
        procedure DoSomething(ARec: TRec);
        property Rec : PRec read FRec; 
      end;
    
    constructor TForm1.Create;
    begin
      inherited;
      FRec := AllocMem(sizeof(TRec));
    end;
    
    destructor TForm1.Destroy;
    begin
      FreeMem(FRec);
    
      inherited;
    end;
    

    Delphi will dereference the PRec pointer for you, so things like this will still work:

    Form1.Rec.A := 1234; 
    

    There's no need for a write part of the property, unless you want to swap the PRec buffer that FRec points at. I really wouldn't suggest to do such swapping via a property anyway.

    0 讨论(0)
  • 2020-12-01 16:54

    Since "Rec" is a property, the compiler treats it a little differently because it has to first evaluate the "read" of the property decl. Consider this, which is semantically equivalent to your example:

    ...
    property Rec: TRec read GetRec write FRec;
    ...
    

    If you look at it like this, you can see that the first reference to "Rec" (before the dot '.'), has to call GetRec, which will create a temporary local copy of Rec. These temporaries are by design "read-only." This is what you're running into.

    Another thing you can do here is to break out the individual fields of the record as properties on the containing class:

    ...
    property RecField: Integer read FRec.A write FRec.A;
    ...
    

    This will allow you to directly assign through the property to the field of that embedded record in the class instance.

    0 讨论(0)
提交回复
热议问题