delphi - Rtti:在类中调用方法时获取“无效的类类型转换”
问题描述
我做了一个我正在尝试做的小工作示例,一切正常,但不是我想用 Rtti 调用方法的部分,检查方法 DoSomeTask 中的注释。我想直视失败的路线比解释要好,但我会尝试的。简而言之,我有一些嵌套类,主要的静态类 TSCSettings 带有一个公共属性 (Users),它是 TUsers 类的一个实例。TUsers 有一个字段 fAccounting,它是 TSettingsAccounting 类的一个实例。这个想法是以这种方式加载用户设置:
TSCSettings.Users.Accounting.LoadSettings(UserID);
并且它工作正常,但是在方法 DoSomeTask 中它无法调用实例 fAccounting 的方法 LoadSettings 与 Rtti 在行
meth.Invoke(vField, [1]); --> 带有消息“无效类类型转换”的异常类 EInvalidCast。
非常感谢你的帮助。
program Rtti_CallMethods;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
RTTI;
type
TSettingsAccounting = Class(TObject)
public
function LoadSettings(UserID: Integer): Boolean;
end;
TUsers = Class(TObject)
strict private
fAccounting: TSettingsAccounting;
public
constructor Create; virtual;
property Accounting: TSettingsAccounting read fAccounting write fAccounting;
function DoSomeTask: Boolean;
end;
//Static class
TSCSettings = Class(TObject)
strict private
class var fUsers: TUsers;
public
class property Users: TUsers read fUsers write fUsers;
class constructor Create;
end;
{ TSettingsAccounting }
function TSettingsAccounting.LoadSettings(UserID: Integer): Boolean;
begin
Writeln('...Task load settings ' + UserID.ToString);
end;
{ TCLUsers }
constructor TUsers.Create;
begin
fAccounting:= TSettingsAccounting.Create;
end;
function TUsers.DoSomeTask: Boolean;
var
vCtx: TRttiContext;
vType: TRttiType;
vField: TRttiField;
meth : TRttiMethod;
sInfo: string;
begin
//---- fAccounting is already instanciated and calling the method in
//this way works fine, but fails when I try to do the same below with Rtti
fAccounting.LoadSettings(4);
//----
vType := vCtx.GetType(self.ClassType); //--> TCLUsers
for vField in vType.GetFields do
begin
sInfo:= vField.Name; // --> fAccounting
//------ This way works fine
meth := vField.FieldType.GetMethod('LoadSettings');
meth.Invoke(fAccounting, [2]);
//------
//------ This way fails: ... exception class EInvalidCast with message 'Invalid class typecast'.
meth.Invoke(vField, [1]);
//------
end;
end;
class constructor TSCSettings.Create;
begin
fUsers:= TUsers.Create;
end;
// -------------------------------
begin
TSCSettings.Users.Accounting.LoadSettings(3); //This works fine
TSCSettings.Users.DoSomeTask;
readln;
end.
解决方案
的第一个参数TRttiMethod.Invoke()
是指向要调用该方法的对象的指针。该指针可以作为直接TObject
指针或作为TValue
包含指针的TObject
指针传入。
在这种情况下,TSettingsAccounting
需要一个对象。这就是为什么meth.Invoke(fAccounting, [2]);
有效。但是在失败的行上,你给它一个指向TRttiField
自身的指针,这就是meth.Invoke(vField, [1]);
失败的原因。TRttiMethod
派生自TObject
,所以代码可以编译,但是TObject
传入是错误的。
您需要TObject
从读取(字段的值)的值,例如:TRttiField
fAccounting
meth.Invoke(vField.GetValue(Self), [1]);
推荐阅读
- reactjs - 为什么使用 immer 的初始值没有变化?
- docker - Docker 容器无法通过 VPN 进行通信
- react-native - 多个叠加层在本机 iOS 中不起作用
- laravel - 干预图像在一张下调整不同图片的大小
- amazon-web-services - 将 docker 映像推送到 aws ecr 不会提供基本的身份验证凭据
- list - 当用户在飞镖中输入索引时搜索列表
- sql - 如果它们存储为字符变化,我如何在 Postgres 上减去两次?
- algorithm - 找不到组匹配算法
- snowflake-cloud-data-platform - 将带有 nextval 的新列添加到现有的 SNOWFLAKE 数据库表
- r - 为使用 ggplot2 生成的图创建下拉菜单