具有单个getter和setter的Delphi属性
我正在尝试实现一个配置文件类包装器,使用单个函数获取和单个函数设置属性值会更容易 下面的代码是我试图实现的最低版本 欢迎任何帮助具有单个getter和setter的Delphi属性,delphi,properties,attributes,rtti,Delphi,Properties,Attributes,Rtti,我正在尝试实现一个配置文件类包装器,使用单个函数获取和单个函数设置属性值会更容易 下面的代码是我试图实现的最低版本 欢迎任何帮助 unit Config; interface uses Rtti; type Group = class(TCustomAttribute) strict private FName: string; public constructor Create(const Name: string); property Name:
unit Config;
interface
uses Rtti;
type
Group = class(TCustomAttribute)
strict private
FName: string;
public
constructor Create(const Name: string);
property Name: string read FName;
end;
IConfig = class
protected
function GetString: string;
procedure SetString(const Value: string);
end;
TConfig = class(IConfig)
public
[Group('Person')]
property Name: string read GetString write SetString;
[Group('Person')]
property City: string read GetString write SetString;
end;
implementation
{ Group }
constructor Group.Create(const Name: string);
begin
FName := Name;
end;
{ IConfig }
function IConfig.GetString: string;
begin
// Here I would need the following from the property that call this function:
// * Property name
// * Property attribute name
// This kind of code will not work, because it loop through all available properties
(*
var
ctx: TRttiContext;
objType: TRttiType;
Prop: TRttiProperty;
begin
ctx := TRttiContext.Create;
objType := ctx.GetType(Obj.ClassInfo);
for Prop in objType.GetProperties do begin
if Prop.GetClassType is TClassBase then
// do something special with base class properties
else
// standard functionality on all other properties
end;
end;
*)
end;
procedure IConfig.SetString(const Value: string);
begin
// Need the same as above
end;
end.
属性getter或setter无法确定访问哪个属性导致调用getter或setter 这种说法的推论是,你要求做的事是不可能的
至于如何解决你的根本问题,我不想对这个问题作太多的详细推测。这可能对你有用。但是,如果不知道您面临的实际问题,我觉得没有资格详细讨论。属性获取程序和设置程序不知道调用它们的是哪个属性。共享getter/setter知道这一点的唯一方法是使用
索引
说明符,例如:
unit Config;
interface
uses Rtti;
type
Group = class(TCustomAttribute)
strict private
FName: string;
public
constructor Create(const Name: string);
property Name: string read FName;
end;
IConfig = class
protected
function GetString(Index: Integer): string;
procedure SetString(Index: Integer; const Value: string);
end;
TConfig = class(IConfig)
public
[Group('Person')]
property Name: string index 0 read GetString write SetString;
[Group('Person')]
property City: string index 1 read GetString write SetString;
end;
implementation
{ Group }
constructor Group.Create(const Name: string);
begin
FName := Name;
end;
{ IConfig }
function IConfig.GetString(Index: Integer): string;
begin
case Index of
0: begin // Name
...
end;
1: begin // City
...
end;
...
end;
end;
procedure IConfig.SetString(Index: Integer; const Value: string);
begin
// same as above
end;
end.
如果getter/setter需要知道属性名称,则可以使用RTTI查找具有相应的索引
值的属性,如果找到,则还可以访问其属性,例如:
function GetPropNameAndGroup(Cls: TClass; PropIndex: Integer; var PropName, GroupName: String): Boolean;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Attr: TCustomAttribute;
begin
PropName := '';
GroupName := '';
Ctx := TRttiContext.Create;
for Prop in Ctx.GetType(Cls).GetProperties do
begin
if (Prop as TRttiInstanceProperty).Index = PropIndex then
begin
PropName := Prop.Name;
for Attr in Prop.GetAttributes do
begin
if Attr is Group then
begin
GroupName := Group(Attr).Name;
Break;
end;
end;
Break;
end;
end;
Result := (PropName <> '') and (GroupName <> '');
end;
function IConfig.GetString(Index: Integer): string;
var
PropName, GroupName: string;
begin
if GetPropNameAndGroup(ClassType, Index, PropName, GroupName) then
begin
//...
end;
end;
procedure IConfig.SetString(Index: Integer; const Value: string);
var
PropName, GroupName: string;
begin
if GetPropNameAndGroup(ClassType, Index, PropName, GroupName) then
begin
//...
end;
end;
函数GetPropNameAndGroup(Cls:TClass;PropIndex:Integer;var-PropName,GroupName:String):布尔;
变量
Ctx:trtti上下文;
财产:信托财产;
属性:TCustomAttribute;
开始
PropName:='';
组名:='';
Ctx:=TRttiContext.Create;
对于Ctx.GetType(Cls.GetProperties)中的Prop
开始
如果(作为TrtInstanceProperty的属性)。索引=ProIndex,则
开始
PropName:=道具名称;
对于Prop.GetAttributes中的Attr
开始
如果Attr是Group,那么
开始
GroupName:=组(Attr).Name;
打破
结束;
结束;
打破
结束;
结束;
结果:=(PropName“”)和(GroupName“”);
结束;
函数IConfig.GetString(索引:整数):字符串;
变量
PropName,GroupName:string;
开始
如果GetPropNameAndGroup(类类型、索引、PropName、GroupName),则
开始
//...
结束;
结束;
过程IConfig.SetString(索引:整数;常量值:字符串);
变量
PropName,GroupName:string;
开始
如果GetPropNameAndGroup(类类型、索引、PropName、GroupName),则
开始
//...
结束;
结束;
这是不正确的。在Delphi中,您可以为属性指定一个索引
说明符,该说明符将成为getter和setter的额外参数。@lase这是真的。但是这个问题并没有问索引属性。我的理解是,因为他问如何添加一个getter和setter来处理属性。@Lasse No他想通过某种魔法找到属性,然后读取附加到属性的属性,然后基于该属性访问一个值。事实上,他没有问如何使用RTTI和属性执行此操作,它只是在源代码中,显示了他迄今为止所做的尝试。是否要执行类似的操作?