Delphi 通过RTTI在字段中记录值
我们需要使用带有预设值的rtti创建一个类。这些值取自属性。当您需要在该领域增加价值时,一切似乎都很好。找到正确的属性并获取属性的值为true。但这一记录并未被操作。告诉我哪里错了Delphi 通过RTTI在字段中记录值,delphi,Delphi,我们需要使用带有预设值的rtti创建一个类。这些值取自属性。当您需要在该领域增加价值时,一切似乎都很好。找到正确的属性并获取属性的值为true。但这一记录并未被操作。告诉我哪里错了 program DemoGenerator; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Rtti; Type // My attribute DemoDataAttribute = class(TCustomAttribu
program DemoGenerator;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Rtti;
Type
// My attribute
DemoDataAttribute = class(TCustomAttribute)
private
FGenerator: String;
public
constructor Create(Generator: String);
published
property Generator: string read FGenerator write FGenerator;
end;
//
TSomeType = Class
private
fPhone: string;
published
[DemoData('+1800764328')]
property Phone: string read fPhone write fPhone;
End;
//
TMegaSuperClass = Class
Function Go<T: Class, constructor>: T;
End;
Procedure Test;
var
LMsc: TMegaSuperClass;
New: TSomeType;
Begin
LMsc := TMegaSuperClass.Create;
try
New := LMsc.Go<TSomeType>;
Writeln('New.Phone: ' + New.Phone);
finally
LMsc.Free;
// New.Free;
end;
End;
{ DemoDataAttribute }
constructor DemoDataAttribute.Create(Generator: String);
begin
FGenerator := Generator;
end;
{ TMegaSuperClass }
function TMegaSuperClass.Go<T>: T;
var
LContext: TRttiContext;
LClass: TRttiInstanceType;
LProp: TRttiProperty;
LAttr: TCustomAttribute;
LField: TRttiField;
begin
// Init Rtti
LContext := TRttiContext.Create;
LClass := LContext.GetType(T) as TRttiInstanceType;
Writeln('LClass: ' + LClass.ToString);
// Result
Result := T.Create;
for LProp in LClass.GetProperties do
begin
Writeln('LProp: ' + LProp.ToString);
for LAttr in LProp.GetAttributes do
begin
Writeln('LAttr: ' + LAttr.ToString);
if LAttr is DemoDataAttribute then
Begin
Writeln('Attr value: ' + DemoDataAttribute(LAttr).Generator);
// How write value?
LProp.SetValue(@Result, DemoDataAttribute(LAttr).Generator);
End;
end;
end;
end;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
Test;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
程序演示生成器;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils,
系统Rtti;
类型
//我的属性
DemoDataAttribute=类(TCustomAttribute)
私有的
FGenerator:字符串;
公众的
构造函数创建(生成器:字符串);
出版
属性生成器:字符串读取FGenerator写入FGenerator;
结束;
//
TSomeType=Class
私有的
fPhone:字符串;
出版
[解调数据('+1800764328')]
物业电话:字符串读fPhone写fPhone;
结束;
//
TMegaSuperClass=类
功能Go:T;
结束;
程序测试;
变量
LMsc:tmega超类;
新:TSomeType;
开始
LMsc:=TMegaSuperClass.Create;
尝试
新:=LMsc.Go;
Writeln('New.Phone:'+New.Phone);
最后
LMsc.免费;
//新的。免费的;
结束;
结束;
{DemoDataAttribute}
构造函数dematataAttribute.Create(生成器:字符串);
开始
FGenerator:=发电机;
结束;
{tmega超类}
函数TMegaSuperClass.Go:T;
变量
LContext:trttitcontext;
l类:trttInstanceType;
LProp:trtti属性;
LAttr:TCustomAttribute;
LField:TRttiField;
开始
//初始Rtti
LContext:=TRttiContext.Create;
LClass:=LContext.GetType(T)作为TRttiInstanceType;
Writeln('LClass:'+LClass.ToString);
//结果
结果:=T.Create;
对于LClass.GetProperties中的LProp
开始
Writeln('LProp:'+LProp.ToString);
对于LProp.GetAttributes中的LAttr
开始
Writeln('LAttr:'+LAttr.ToString);
如果LAttr是DemoDataAttribute,则
开始
Writeln('Attr value:'+DemoDataAttribute(LAttr.Generator));
//如何写值?
LProp.SetValue(@Result,DemoDataAttribute(LAttr.Generator));
结束;
结束;
结束;
结束;
开始
尝试
{TODO-oUser-cConsole Main:在此处插入代码}
试验;
Readln;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
结束。
控制台输出:
TSomeType酒店电话:字符串
解调器属性
值:+1800764328
电话: 像这样:
LProp.SetValue(Pointer(Result), DemoDataAttribute(LAttr).Generator);
SetValue
的第一个参数声明为Instance:Pointer
。类引用只是指向实例的指针,这正是您所需要的。我认为对指针的强制转换是必要的,但现在无法检查。强制转换是必需的(否则不会编译)。您也可以这样强制转换:TObject(Result)
,它也可以工作。问题是,我真的不明白为什么需要这样的强制转换,因为编译器可以利用泛型上的当前约束(类和构造函数约束不应该暗示TObject后代吗?)