Rtti:在 class 中调用方法时得到 "Invalid class typecast"
Rtti: getting "Invalid class typecast" when calling a method in a class
我做了一个我正在尝试做的小工作示例,一切正常,但不是我想用 Rtti 调用方法的部分,请检查方法 DoSomeTask 中的注释。
我想直视失败的行比解释更好,但我会尝试。简而言之,我有一些嵌套的 classes,主要的静态 class TSCSettings 和 public 属性(用户)是 class TUsers 的一个实例。 TUsers 有一个字段 fAccounting,它是 class TSettingsAccounting 的一个实例。这个想法是以这种方式加载用户设置:
TSCSettings.Users.Accounting.LoadSettings(用户ID);
它像那样工作得很好,但是在方法 DoSomeTask 中,它无法调用实例 fAccounting 的方法 LoadSettings,行中有 Rtti
meth.Invoke(vField, [1]); --> 异常 class EInvalidCast 消息 'Invalid class typecast'.
非常感谢您的帮助。
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
指针或作为包含 TObject
指针的 TValue
传递。
在这种情况下,需要一个 TSettingsAccounting
对象。这就是 meth.Invoke(fAccounting, [2]);
起作用的原因。但是在失败的行上,你给它一个指向 TRttiField
本身的指针,这就是 meth.Invoke(vField, [1]);
失败的原因。 TRttiMethod
源自TObject
,所以代码编译,但是传入错误TObject
您需要 TObject
从阅读 TRttiField
的 value(value fAccounting
字段),例如:
meth.Invoke(vField.GetValue(Self), [1]);
我做了一个我正在尝试做的小工作示例,一切正常,但不是我想用 Rtti 调用方法的部分,请检查方法 DoSomeTask 中的注释。 我想直视失败的行比解释更好,但我会尝试。简而言之,我有一些嵌套的 classes,主要的静态 class TSCSettings 和 public 属性(用户)是 class TUsers 的一个实例。 TUsers 有一个字段 fAccounting,它是 class TSettingsAccounting 的一个实例。这个想法是以这种方式加载用户设置:
TSCSettings.Users.Accounting.LoadSettings(用户ID);
它像那样工作得很好,但是在方法 DoSomeTask 中,它无法调用实例 fAccounting 的方法 LoadSettings,行中有 Rtti
meth.Invoke(vField, [1]); --> 异常 class EInvalidCast 消息 'Invalid class typecast'.
非常感谢您的帮助。
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
指针或作为包含 TObject
指针的 TValue
传递。
在这种情况下,需要一个 TSettingsAccounting
对象。这就是 meth.Invoke(fAccounting, [2]);
起作用的原因。但是在失败的行上,你给它一个指向 TRttiField
本身的指针,这就是 meth.Invoke(vField, [1]);
失败的原因。 TRttiMethod
源自TObject
,所以代码编译,但是传入错误TObject
您需要 TObject
从阅读 TRttiField
的 value(value fAccounting
字段),例如:
meth.Invoke(vField.GetValue(Self), [1]);