Property/ru
│
Deutsch (de) │
English (en) │
suomi (fi) │
français (fr) │
русский (ru) │
Назад к Зарезервированным словам.
Зарезервированное слово property
является частью объектно-ориентированного программирования. В русской терминологии обозначается как свойство. Свойства позволяют разграничить доступ (чтение, запись и т.д.) к полям внутри класса.
Синтаксис
Идентификатор
Название идентификатора PropertyName должно соответствовать правиламObject Pascal.
Тип данных
Тип данных <type> может использоваться любой, доступный для применения у полей класса. Так же, когда спецификаторами read
и write
выбрано поле класса, тип свойства должен соответствовать типу этого поля. Пример:
TMyClass = class
private
FNumber: Integer;
public
property Number: Integer read FNumber write FNumber;
end;
В том случае, когда чтение происходит через функцию, результат функции должен имет тот же тип что и у свойства. Пример:
TMyClass = class
private
function getNumber: Integer;
public
property Number: Integer read getNumber;
end;
Спецификаторы
необязательный | |
обязательный | |
требует определённого поведения, указанного после значка. | |
подразумевает совместное использование |
Спецификаторы имеют свой определённый порядок объявления:
Спецификаторы разделяются на обязательные и не обязательные. Обязательными являются read
и write
. Причём достаточно использовать один из них. К примеру следующий код:
TMyClass = class
private
FNumber: Integer;
public
property Number: Integer read FNumber;
end;
Является полностью корректным. В данном случае свойство Number
может быть только прочитано, так как спецификатор write
здесь отсутствует.
index | <0..High(Integer)> | |
read | <function getPropertyName(Index: Integer): <type>> | |
write | <procedure setPropertyName(Index: Integer; const Value: <type>)> |
Спецификатор index
позволяет обращаться к множеству имён свойств, поддерживаемых единственным методом доступа. Пример:
{$mode objfpc}
Type
TPoint = class
private
FX,FY : Longint;
function GetCoord (Index : Integer): Longint;
procedure SetCoord (Index : Integer; Value : longint);
public
property X : Longint index 1 read GetCoord write SetCoord;
property Y : Longint index 2 read GetCoord write SetCoord;
property Coords[Index : Integer]:Longint read GetCoord;
end;
Procedure TPoint.SetCoord (Index : Integer; Value : Longint);
begin
Case Index of
1 : FX := Value;
2 : FY := Value;
end;
end;
Function TPoint.GetCoord (INdex : Integer) : Longint;
begin
Case Index of
1 : Result := FX;
2 : Result := FY;
end;
end;
Var
P : TPoint;
begin
P := TPoint.create;
P.X := 2;
P.Y := 3;
With P do
WriteLn ('X=',X,' Y=',Y);
end.
read | <function getPropertyName: <type>> | |
<FField> | ||
<function getPropertyName(ident: <type>; ...): <type>> |
Спецификатор доступа, определяющий метод для чтения (геттер). Может быть полем или методом объекта, являющимся функцией.
Пример свойства, когда чтение происходит напрямую у поля объекта:
TMyClass = class
private
FNumber: Integer;
public
property Number: Integer read FNumber;
end;
Пример свойства, когда чтение происходит через геттер-функцию:
{ TMyClass }
TMyClass = class
private
FNumber: Integer;
function getNumber: Integer;
public
property Number: Integer read getNumber;
end;
{ TMyClass }
function TMyClass.getNumber: Integer;
begin
Result := FNumber;
end;
В том случае, когда свойство является свойством-массивом, спецификатор должен быть реализован через функцию с параметрами, дублирующими типы данных параметров, указанных в квадратных скобках после идентификатора свойства и иметь ту же последовательность. Пример:
unit Unit2;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils;
type
{ TMyClass }
TMyClass = class
private
FMother, FFather, FChild: String;
function getMember(const MemberName: String): String;
public
property Family[MemberName: String]: String read getMember;
end;
implementation
{ TMyClass }
function TMyClass.getMember(const MemberName: String): String;
var processed_MemberName: String;
begin
Result := '';
processed_MemberName := LowerCase(MemberName);
case processed_MemberName of
'mother': Result := FMother;
'father': Result := FFather;
'child': Result := FChild;
end;
end;
end.
write | <procedure setPropertyName(const Value: <type>)> | |
<FField> | ||
<procedure setPropertyName(ident: <type>; ...; const Value: <type>)> |
Спецификатор доступа, определяющий метод для записи (сеттер). Может быть полем или методом объекта, являющимся процедурой.
Пример свойства, когда запись происходит напрямую у поля объекта:
TMyClass = class
private
FNumber: Integer;
public
property Number: Integer write FNumber;
end;
Пример свойства, когда запись происходит через сеттер-функцию:
{ TMyClass }
TMyClass = class
private
FNumber: Integer;
procedure setNumber(const Value: Integer): Integer;
public
property Number: Integer write setNumber;
end;
{ TMyClass }
function TMyClass.setNumber(const Value: Integer): Integer;
begin
FNumber := Value;
end;
В том случае, когда свойство является свойством-массивом, спецификатор должен быть реализованы через процедуру с параметрами, дублирующими типы данных параметров, указанных в квадратных скобках после идентификатора свойства и иметь ту же последовательность. Пример:
unit Unit2;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils;
type
{ TMyClass }
TMyClass = class
private
FMother, FFather, FChild: String;
function getMember(const MemberName: String): String;
procedure setMember(const MemberName: String; const Value: String);
public
property Family[MemberName: String]: String read getMember write setMember;
end;
implementation
{ TMyClass }
function TMyClass.getMember(const MemberName: String): String;
var processed_MemberName: String;
begin
Result := '';
processed_MemberName := LowerCase(MemberName);
case processed_MemberName of
'mother': Result := FMother;
'father': Result := FFather;
'child': Result := FChild;
end;
end;
procedure TMyClass.setMember(const MemberName: String; const Value: String);
var processed_MemberName: String;
begin
processed_MemberName := LowerCase(MemberName);
case processed_MemberName of
'mother': FMother := Value;
'father': FFather := Value;
'child': FChild := Value;
end;
end;
end.
Спецификатор потоковой передачи, определяющий будет ли свойство хранится в файле формы. Может быть булевой константой, полем объекта или методом (функцией) без параметров с результатом в виде булевого значения. Отсутствие данного спецификатора эквивалентно True
. Пример:
uses Math;
TMyClass = class
private
FNumberInt: Integer;
FNumberReal: Real;
FNumberReal_2: Real;
FMyString: String;
IsStored: Boolean;
function isStoredNumberReal_2: Boolean;
public
property NumberInt: Integer read FNumberInt write FNumberInt stored False;
property NumberReal: Real read FNumberReal write FNumberReal stored IsStored;
property NumberReal: Real read FNumberReal write FNumberReal stored IsStored;
property MyString: String read FMyString write FMyString; // эквивалентно True
end;
TMyClass.isStoredNumberReal_2: Boolean;
begin
if CompareValue(FNumberReal_2, 3.14) <> 0 then
Result := True
else
Result := False;
end;
Данный спецификатор связан с спецификатором default
и nodefault
. Когда значение свойства равно значению, указанному после default
, данное свойство не будет сохранено в файле формы.
implements | <IInterface> |
Спецификатор для делегирования реализации интерфейсов агрегируемому объекту (входящий в состав вашего объекта и являющийся его полем). Пример:
IRadio = interface
procedure Increment;
procedure Decrement;
end;
IRecorder = interface
procedure StartRecord;
procedure Play;
end;
TRadio = class(TInterfacedObject, IRadio)
private
FVolume : Integer;
procedure SetVolume(const Value: Integer);
public
procedure Increment;
procedure Decrement;
property Volume: Integer read FVolume write SetVolume;
Destructor Destroy; override;
end;
TRadioRecorder = class(TInterfacedObject, IRadio, IRecorder)
private
FRadio: TRadio;
procedure SetRadio(const Value: TRadio):
public
procedure StartRecord;
procedure Play;
constructor Create;
property Radio: TRadio read FRadio write SetRadio implements IRadio;
end;
Данный спецификатор может применяться тремя способами. Первый способ это определения массива свойств объекта по умолчанию. Что позволит ссылаться на множество значений, используя одно и то же имя свойства. Например:
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TMyClass }
TMyClass = class
private
FNumbers: array [0..2] of Integer;
function getNumber(const Index: Integer): Integer;
procedure setNumber(const Index: Integer; const Value: Integer);
public
property Numbers[Index: Integer]: Integer read getNumber write setNumber; default;
end;
implementation
{ TMyClass }
function TMyClass.getNumber(const Index: Integer): Integer;
begin
Result := FNumbers[Index];
end;
procedure TMyClass.setNumber(const Index: Integer; const Value: Integer);
begin
FNumbers[Index] := Value;
end;
end.
Вы можете не использовать массив в качестве места хранения значений, а определять их через функции, но само свойство должно оставаться свойством-массивом.
Так же стоит отметить несколько вещей. Во-первых, при использовании данного спецификатора с свойством-массивом, объявление default
должно быть после всех спецификаторов через точку с запятой. Во-вторых данный способ не применим к простым типам, но есть возможность работы с внутренним объектом. В-третьих вы не можете определить два свойства-массива по умолчанию. Зато при наследовании вы можете его переназначить.
Второй способ связан с спецификатором stored
. Данный способ работает только с порядковыми типами. В даннмо случае спецификатор default
будет определять необходимость сохранения свойства в файл формы путём сравнения с конкретным значением. При создании экземпляра класса значение по умолчанию не применяется автоматически к свойству, ответственность за выполнение этого в конструкторе класса лежит на программисте. Пример:
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TMyClass }
TMyClass = class
private
FNumber: Integer;
public
constructor Create;
property Number: Integer read FNumber write FNumber default 10;
end;
implementation
{ TMyClass }
constructor TMyClass.Create;
begin
FNumber := 10;
end;
end.
Третьим способом является использование спецификатора для обозначения значения у свойства по умолчанию. Напоминаем, что при создании экземпляра класса значение по умолчанию не применяется автоматически к свойству, ответственность за выполнение этого в конструкторе класса лежит на программисте.
Спецификатор потоковой передачи. Может использоваться для обозначения, что свойство не имеет значения по умолчанию. Пр использовании с stored
, обозначает, что свойство должно сохраняться в файл формы, если stored
имеет значение True
.