Это отличный вопрос!
Поведение, которое вы видите, является следствием деталей реализации свойств.То, как компилятор реализует свойства, отличается для прямых методов получения свойства поля и для методов получения свойства функции.
Когда вы пишете
Rec.A := 21;
Компилятор видит Rec
и знает, что это свойство.Поскольку метод получения является прямым методом получения поля, компилятор просто заменяет Rec
на FRec
и компилирует код в точности так, как если бы вы написали
FRec.A := 21;
. Затем компилятор обнаруживает свойство A
и используетметод установки, и поэтому ваше назначение становится
FRec.SetA(21);
Отсюда и поведение, которое вы наблюдали.
Предположим, что вместо получателя прямого поля у вас была функция получателя
property Rec: TRec read GetRec;
....
function TForm1.GetRec: TRec;
begin
Result := FRec;
end;
В этом сценарии обработка
Rec.A := 21;
изменяется.Вместо этого компилятор объявляет неявную локальную переменную, а код компилируется следующим образом:
var
__local_rec: TRec;
....
__local_rec := GetRec;
__local_rec.A := 21;
Мне кажется очевидным, что поведение такой программы не должно зависеть от того, является ли свойство getterпрямой полевой получатель или получатель функции.Это похоже на конструктивный недостаток во взаимодействии между функцией свойства и расширенной функцией записи.
Вот полная программа, которая очень кратко демонстрирует проблему:
{$APPTYPE CONSOLE}
type
TRec = record
private
FA: Integer;
procedure SetA(const Value: integer);
public
property A: integer read FA write SetA;
end;
procedure TRec.SetA(const Value: integer);
begin
FA := Value;
end;
type
TMyClass = class
private
FRec: TRec;
function GetRec: TRec;
public
property RecDirect: TRec read FRec;
property RecFunction: TRec read GetRec;
end;
var
Obj: TMyClass;
function TMyClass.GetRec: TRec;
begin
Result := FRec;
end;
begin
Obj := TMyClass.Create;
Obj.RecDirect.A := 21;
Writeln(Obj.FRec.FA);
Obj := TMyClass.Create;
Obj.RecFunction.A := 21;
Writeln(Obj.FRec.FA);
end.
Выход
21
0