Delphi 如何存储对变量的trtti方法引用?
我想存储一个在编译时不知道的类的构造函数方法,以便稍后调用它来创建指定类的对象。如果可能的话,我不想使用TClass.Create,因为它不调用对象的默认构造函数 下面是重现问题的代码:Delphi 如何存储对变量的trtti方法引用?,delphi,rtti,Delphi,Rtti,我想存储一个在编译时不知道的类的构造函数方法,以便稍后调用它来创建指定类的对象。如果可能的话,我不想使用TClass.Create,因为它不调用对象的默认构造函数 下面是重现问题的代码: uses System.SysUtils, Rtti; type TClass1 = class constructor Create(pInt: Integer); end; constructor TClass1.Create(pInt: Integer); begin end;
uses
System.SysUtils,
Rtti;
type
TClass1 = class
constructor Create(pInt: Integer);
end;
constructor TClass1.Create(pInt: Integer);
begin
end;
procedure PrintMethod(FMethod: TRttiMethod);
begin
writeln(Format('Address: %d, Value Adress: %d, Method: %s, Handle: %d, Params: %d, ClassName: %s',
[Integer(FMethod), Integer(Addr(FMethod)), FMethod.Name, Integer(FMethod.Handle), Length(FMethod.GetParameters), FMethod.Parent.AsInstance.MetaclassType.ClassName]));
end;
function FindCreateMethod(pClass: TClass): TRttiMethod;
var
rContext: TRttiContext;
rType: TRttiType;
FMethods: TArray<TRttiMethod>;
I: Integer;
begin
rContext:= TRttiContext.Create;
rType:= rContext.GetType(pClass);
FMethods:= rType.GetMethods;
for I:= Low(FMethods) to High(FMethods) do
if SameText('Create', FMethods[I].Name) then
begin
Result:= FMethods[I];
Break;
end;
PrintMethod(Result);
end;
var
FMethod: TRttiMethod;
begin
FMethod:= FindCreateMethod(TClass1);//Prints: Address: 39354896, Value Adress: 1703672, Method: Create, Handle: 4654648, Params: 1, ClassName: TClass1
// Outside the scope of the function FindCreateMethod GetParameters does not work for FMethod
PrintMethod(FMethod); //Prints: Address: 39354896, Value Adress: 1703740, Method: Create, Handle: 4654648, Params: 0, ClassName: TClass1
with TRttiContext.Create do
GetType(TClass1).GetMethods; // After GetMethods call the value of FMethod changes
PrintMethod(FMethod); //Prints: Address: 39354896, Value Adress: 1703740, Method: Destroy, Handle: 4200544, Params: 0, ClassName: TObject
readln;
end.
这是怎么回事?显然,每次调用GetMethods时,它都会为该类型重新创建TRTTIMethod实例。是否有一种可靠的方法来存储TRttiMethod实例,而不必每次循环所有方法
我正在使用Delphi Berlin 10.1更新2
已解决:由于@RemyLebeau comment,通过使用全局TRTTiContext实例解决了问题。显然,TRTTIContext中有引用计数的信息,而且,由于TRTTIContext的唯一实例是我在FindCreateMethod函数中创建的实例,当它超出范围时,引用计数变为0,TRTTIMethods实例丢失。多亏@RemyLebeau的注释,通过使用全局TRTTiContext实例解决了问题。显然,TrtitContext中有引用计数的信息,而且,由于TrtitContext的唯一实例是我在FindCreateMethod函数中创建的实例,当它超出范围时,引用计数变为0,TrtitMethods实例丢失。FYI,并非所有类构造函数都命名为“Create”。您应该检查mkConstructor的TRTTIMethod.MethodKind属性或调用TRTTIMethod.IsConstructor方法,而不是专门检查'Create'的TRTTIMethod.Name属性。此外,在内部,TRTTIMethod对象和其他RTTI对象由TRTTIContext内引用的引用计数单例对象维护,因此仅在该对象保持活动状态时才有效。对于您正在尝试的内容,您应该创建一个全局TRTTIContext,以使RTTI单例在程序的生命周期内保持活动状态。即使您在每次搜索时都创建了一个新的TRTTIContext,您也不想一遍又一遍地重新创建singleton。@Remy Lebeau感谢您提供了有关检查方法类型的提示,我一定会使用它。将更改测试应用程序以使用全局上下文,并返回结果。无论如何,如果必须依赖TRttiContext,我认为我无法存储trtticonthod实例。只能调用一次Create。可以调用TRttiContext.Create多次。但是您应该保留一个全局trtti上下文,这样当您有多个呼叫时,访问RTTI的效率更高。@MarceloRauter,请添加您最后的编辑作为答案,而不是将其嵌入问题中。是的,在使用RTTI时,使用TRTTIContext作为全局避免了一些难以发现的错误。