Delphi 如何存储对变量的trtti方法引用?

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;

我想存储一个在编译时不知道的类的构造函数方法,以便稍后调用它来创建指定类的对象。如果可能的话,我不想使用TClass.Create,因为它不调用对象的默认构造函数

下面是重现问题的代码:

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作为全局避免了一些难以发现的错误。