Delphi:通过RTTI获取/设置属性时未应用方法解析子句
我试图通过对各种接口属性使用方法解析子句,将功能添加到现有代码中 虽然这样做很好,但在代码中获取/设置属性时,在尝试通过RTTI设置或获取属性时失败 使用RTTI时,将调用第一个实现类方法 下面是显示问题的代码:Delphi:通过RTTI获取/设置属性时未应用方法解析子句,delphi,rtti,Delphi,Rtti,我试图通过对各种接口属性使用方法解析子句,将功能添加到现有代码中 虽然这样做很好,但在代码中获取/设置属性时,在尝试通过RTTI设置或获取属性时失败 使用RTTI时,将调用第一个实现类方法 下面是显示问题的代码: program TestIntfMethodResolutions; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Variants, System.Classes, TypInfo, R
program TestIntfMethodResolutions;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Variants,
System.Classes,
TypInfo,
RTTI{,
uRTTIHelper};
type
ITestInterface = interface
['{61553B5F-574A-4B0F-AB6F-0560E324B463}']
function GetA:integer;
procedure SetA(const AVal:integer);
property A:integer read GetA write SetA;
end;
{$RTTI EXPLICIT METHODS([vcPrivate,vcPublic])}
TTintimpl1 = class(TInterfacedObject,ITestInterface)
private
FA:integer;
function GetA: integer;
procedure SetA(const Value: integer);virtual; // Does not need to be virtual
public
property A:integer read GetA write SetA;
end;
{$RTTI EXPLICIT METHODS([vcPrivate,vcPublic])}
//Explicit RTTI settings causes the Private methods to show up in the method list
TIntimpl2 = class(TTIntimpl1,ITestInterface)
private
procedure MySetA(const Value:integer);virtual;
public
procedure ITestInterface.SetA = MySetA;
end;
TMain = class
private
{ Private declarations }
public
{ Public declarations }
procedure FormCreate;
end;
var
Form5: TMain;
procedure TMain.FormCreate;
var
ctx:TRttiContext;
avalue,bvalue:tvalue;
atype,bastyp:TRttiType;
aproplist:Tarray<TRttiProperty>;
amethlist:Tarray<TRttiMethod>;
isinst:boolean;
aninst:TRttiInstanceType;
anintf:TRttiInterfaceType;
intflist:Tarray<TRttiInterfaceType>;
inst:pointer;
anint:ITestInterface;
aprop:TRttiProperty;
codeptr:pointer;
asetmeth:TRTTIMethod;
begin
ctx:=TRttiContext.Create;
//Faxisloopthr:=TIntimpl2.Create;
anint:=TIntimpl2.Create;
avalue:=anint as TObject;
atype:=ctx.GetType(avalue.TypeInfo);
if atype.IsInstance then
begin
aninst:=atype.AsInstance;
aproplist:=aninst.GetProperties;
amethlist:=aninst.GetMethods;
bvalue:=TValue.FromOrdinal(aproplist[0].PropertyType.Handle,1);
inst:=avalue.AsObject;
aprop:=aproplist[0]; //I could have called aproplist[0].SetValue(...
aprop.SetValue(inst,bvalue);
end;
writeln('RTTI result '+anint.A.ToString); //Should give me 20 but I get 10 everytime
//asetmeth:=aprop.SetterMethod(inst); // returns SetA and not MySetA - need uRTTIhelper unit. https://github.com/RRUZ/blog/tree/master/RTTI
// setpropvalue(inst,aprop.PropInfo,bvalue.AsVariant); // calls SetA and not MySetA
//Manually setting the value calls the correct method
anint.A:=1;
writeln('Direct setting '+anint.A.ToString);
end;
{ T2ndIntf }
{ TTintimpl1 }
function TTintimpl1.GetA: integer;
begin
Result:=FA;
end;
procedure TTintimpl1.SetA(const Value: integer);
var
a:integer;
begin
FA:=Value*10;
writeln('In SetA ',FA);
end;
{ TIntimpl2 }
//Should get called - but the 1st implementing parent gets called
procedure TIntimpl2.MySetA(const Value: integer);
begin
FA:=Value*20;
writeln('In MySetA ',FA);
end;
begin
Form5:=TMain.Create;
try
Form5.FormCreate;
finally
Form5.Free;
readln;
end;
end.
程序测试分辨率;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils,
系统变量,
系统,班级,,
TypInfo,
RTTI{,
uRTTIHelper};
类型
ITestInterface=接口
[{61553B5F-574A-4B0F-AB6F-0560E324B463}]
函数GetA:integer;
过程SetA(常数AVal:整数);
属性A:整数读取GetA写入SetA;
结束;
{$RTTI显式方法([vcPrivate,vcPublic])}
TTintimpl1=类(TInterfacedObject,ITestInterface)
私有的
FA:整数;
函数GetA:integer;
程序SetA(常量值:整数);虚拟的;//不需要是虚拟的
公众的
属性A:整数读取GetA写入SetA;
结束;
{$RTTI显式方法([vcPrivate,vcPublic])}
//显式RTTI设置会导致私有方法显示在方法列表中
TIntimpl2=类(TTIntimpl1,ITestInterface)
私有的
过程MySetA(常量值:整数);事实上的
公众的
程序ITestInterface.SetA=MySetA;
结束;
TMain=类
私有的
{私有声明}
公众的
{公开声明}
程序表单创建;
结束;
变量
表5:TMain;
程序TMain.FormCreate;
变量
ctx:trtti上下文;
avalue,bvalue:tvalue;
atype,bastyp:trttype;
停机坪医师:柏油;
名单:焦油;
isinst:布尔型;
列表:trttInstanceType;
anintf:trtti接口类型;
intflist:Tarray;
仪器:指针;
提示:ITestInterface;
aprop:trtti属性;
编码器:指针;
asetmeth:trtti法;
开始
ctx:=TRttiContext.Create;
//Faxisloopthr:=tintinimpl2.Create;
anint:=2.Create;
avalue:=作为对象的信息;
atype:=ctx.GetType(avalue.TypeInfo);
如果atype.IsInstance,则
开始
Anist:=atype.AsInstance;
aproplist:=一个st.GetProperties;
amethlist:=anist.GetMethods;
bvalue:=TValue.FromOrdinal(aproplist[0]。PropertyType.Handle,1);
inst:=avalue.AsObject;
aprop:=aproplist[0]//我本可以调用aproplist[0]。SetValue(。。。
近似设定值(仪表、B值);
结束;
writeln('RTTI result'+anint.A.ToString);//应该给我20,但每次我都得到10
//asetmeth:=aprop.SetterMethod(inst);//返回SetA而不是MySetA-需要uRTTIhelper单元。https://github.com/RRUZ/blog/tree/master/RTTI
//setpropvalue(inst,aprop.PropInfo,bvalue.AsVariant);//调用SetA而不是MySetA
//手动设置该值将调用正确的方法
A:=1;
writeln(‘直接设置’+int.A.ToString);
结束;
{T2ndIntf}
{TTintimpl1}
函数TTintimpl1.GetA:integer;
开始
结果:=FA;
结束;
程序TTintimpl1.SetA(常量值:整数);
变量
a:整数;
开始
FA:=值*10;
书面语(“SetA”,FA);
结束;
{2}
//应该被调用-但是第一个实现的父级被调用
过程2.MySetA(常量值:整数);
开始
FA:=值*20;
书面形式(“在迈塞塔”,FA);
结束;
开始
Form5:=TMain.Create;
尝试
Form5.FormCreate;
最后
表格5.免费;
readln;
结束;
结束。
我做错了什么
谢谢
伊布。
Delphi 10.2 Tokyo Win64如果不使用interface@DavidHeffernan-只有在使用RTTI时才会忽略接口解析。当我在代码中设置属性时,它会按预期工作。您能指导我如何正确地设置声明的接口属性吗g RTTI。谢谢。你需要通过接口。你的RTTI代码通过类。谢谢David。是的,当我通过接口访问方法时,它可以工作。但不幸的是,没有为接口属性生成RTTI(正如有人所说)只是语法糖。重写逻辑更容易避免麻烦的接口。无论如何,谢谢。你必须直接调用属性getter和setter,但是你可以通过RTTI来实现