Jer*_*dge 11 delphi properties delphi-xe2
我想把记录作为对象的属性.问题是,当我更改此记录的其中一个字段时,该对象不知道该更改.
type
TMyRecord = record
SomeField: Integer;
end;
TMyObject = class(TObject)
private
FSomeRecord: TMyRecord;
procedure SetSomeRecord(const Value: TMyRecord);
public
property SomeRecord: TMyRecord read FSomeRecord write SetSomeRecord;
end;
Run Code Online (Sandbox Code Playgroud)
如果我这样做......
MyObject.SomeRecord.SomeField:= 5;
Run Code Online (Sandbox Code Playgroud)
...不管用.
那么当记录其中一个记录的字段时,如何使属性设置过程'catch'?也许在如何申报记录方面有一些诀窍?
更多信息
我的目标是避免创建一个TObject
或TPersistent
一个OnChange
事件(例如TFont
或TStringList
).我非常熟悉为此使用对象,但是为了尝试清理我的代码,我看到我是否可以使用Record.我只需要确保在设置其中一个记录字段时可以正确调用我的记录属性设置器.
Dav*_*nan 11
考虑这一行:
MyObject.SomeRecord.SomeField := NewValue;
Run Code Online (Sandbox Code Playgroud)
这实际上是一个编译错误:
[DCC错误]:E2064左侧无法分配
你的实际代码可能是这样的:
MyRecord := MyObject.SomeRecord;
MyRecord.SomeField := NewValue;
Run Code Online (Sandbox Code Playgroud)
这里发生的是您将记录类型的值复制到局部变量MyRecord
.然后,您可以修改此本地副本的字段.这不会修改MyObject中保存的记录.为此,您需要调用属性设置器.
MyRecord := MyObject.SomeRecord;
MyRecord.SomeField := NewValue;
MyObject.SomeRecord := MyRecord;
Run Code Online (Sandbox Code Playgroud)
或者切换到使用引用类型,即类,而不是记录.
总而言之,您当前代码的问题是没有调用SetSomeRecord,而是您正在修改记录的副本.这是因为记录是值类型而不是引用类型.
Bri*_*ost 11
最终,您将需要访问记录的字段,但正如您所建议的那样,记录通常是类中适合的抽象选择.类可以整齐地访问记录的属性,如下所示:
type
TMyRec = record
SomeRecInteger: integer;
SomeRecString: string;
end;
TMyClass = class(TObject)
private
FMyRec: TMyRec;
procedure SetSomeString(const AString: string);
public
property SomeInteger: integer read FMyRec.SomeRecInteger write FMyRec.SomeRecInteger;
property SomeString: string read FMyRec.SomeRecString write SetSomeString;
end;
procedure TMyClass.SetSomeRecString(const AString: string);
begin
If AString <> SomeString then
begin
// do something special if SomeRecString property is set
FMyRec.SomeRecString := AString;
end;
end;
Run Code Online (Sandbox Code Playgroud)
注意:
希望这可以帮助.
使用 TObject 代替 Record 怎么样?
type
TMyProperties = class(TObject)
SomeField: Integer;
end;
TMyObject = class(TObject)
private
FMyProperties: TMyProperties;
public
constructor Create;
destructor Destroy; override;
property MyProperties: TMyRecord read FMyProperties;
end;
implementation
constructor TMyObject.Create;
begin
FMyProperties := TMyProperties.Create;
end;
destructor TMyObject.Destroy;
begin
FMyProperties.Free;
end;
Run Code Online (Sandbox Code Playgroud)
您现在可以像这样读取和设置 TMyProperties 的属性:
MyObject.MyProperties.SomeField := 1;
x := MyObject.MyProperties.SomeField;
Run Code Online (Sandbox Code Playgroud)
使用此方法,您不需要单独从记录获取值或设置值。如果您需要捕获 FMyProperties 中的更改,您可以在属性声明中添加“设置”过程。
为什么不让 setter/getter 成为记录的一部分呢?
TMyRecord = record
fFirstname: string;
procedure SetFirstName(AValue: String);
property
Firstname : string read fFirstname write SetFirstName;
end;
TMyClass = class(TObject)
MyRecord : TMyRecord;
end;
procedure TMyRecord.SetFirstName(AValue: String);
begin
// do extra checking here
fFirstname := AValue;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyClass: TMyClass;
begin
MyClass := TMyClass.Create;
try
MyClass.MyRecord.Firstname := 'John';
showmessage(MyClass.MyRecord.Firstname);
finally
MyClass.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)