zeus
zeus

Reputation: 13345

read write property of type record

Is their any drawback to declare a property of type record ?

  TMyObject = class(TObject)
  private
    FSomeRecord: TMyRecord;
  public
    property SomeRecord: TMyRecord read FSomeRecord write FSomeRecord;
  end;

How the instruction Myobject.SomeRecord.xxx := yyy will work under the hood (I think this can not work actually) ?

If it's can not work, how to do with record property? is it simply better to avoid it and declare TMyobject like below?

  TMyObject = class(TObject)
  public
    SomeRecord: TMyRecord;
  end;

Upvotes: 1

Views: 476

Answers (2)

HeartWare
HeartWare

Reputation: 8243

One way to circumvent this is to declare the property as a POINTER to the record (if you only need access to the fields/methods within the record):

TYPE
  TMyRecord = RECORD
                Field1  : INTEGER;
              END;
  PMyRecord = ^TMyRecord;

TYPE
  TMyClass  = CLASS
          PRIVATE
            FMyRecord   : TMyRecord;
            FUNCTION    GetRec : PMyRecord;
          PUBLIC
            PROPERTY    MyRec : PMyRecord Read GetRec;
          END;

{ TMyClass }

FUNCTION TMyClass.GetRec : PMyRecord;
  BEGIN
    Result:=@FMyRecord
  END;

.
.
.
VAR
  MC    : TMyClass;
.
.
.
MC.MyRec.Field1:=12
.
.
.

Due to the "Extended syntax", you can short-circuit the normal syntax of

MC.MyRec^.Field1:=12

to

MC.MyRec.Field1:=12

but not the following use:

VAR NewRec : TMyRecord := MC.MyRec;

which would have to be coded as

VAR NewRec : TMyRecord := MC.MyRec^;

unless you introduce a RECORD HELPER for the PMyRecord that implements an implicit cast to TMyRecord:

TYPE
  PMyRecHelper  = RECORD HELPER FOR PMyRecord
                    CLASS OPERATOR Implicit(P : PMyRecord) : TMyRecord;
                  END;

{ PMyRecHelper }

CLASS OPERATOR PMyRecHelper.Implicit(P : PMyRecord) : TMyRecord;
  BEGIN
    Result:=P^
  END;

Unfortunately, the above code, while it compiles, doesn't work. Delphi does not allow operator overloaders in record helpers...

So until this last item is implemented, you only have a semi-working implementation...

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 595392

You are correct that Myobject.SomeRecord.xxx := yyy will not work the way you want. It will invoke the property getter, returning a copy of the record, and then you would be updating the xxx field of the copy, not the original. Essentially, the generated code would act like this:

var tmp: TMyRecord;
tmp = Myobject.FSomeRecord;
tmp.xxx := yyy;

Unless you need RTTI for the property, there is no good reason to declare a read+write property that simply accesses a field directly. Just expose public access to the field instead.

Upvotes: 2

Related Questions