8

在以下类型中:

MyClass = class(TInterfacedPersistent)
private
  FMyProperty: Integer;      
published
  procedure setMyProperty(Value: Integer); virtual;
  property MyProperty: Integer read FMyProperty write setMyProperty;

我想通过 RTTI 知道“MyProperty”属性的 setter 方法的名称。我尝试了以下方法:

    procedure ShowSetterMethodsNames(pMyObject: TObject);
    var
      vPropList: TPropList;      
      vCount, I: Integer;
    begin
      vCount:= GetPropList(pMyObject.ClassInfo, tkProperties, @vPropList);

      for I:= 0 to vCount -1 do
      begin
          if Assigned(vPropList[I]^.SetProc) then
            ShowMessage(pMyObject.ClassType.MethodName(vPropList[I]^.SetProc));
      end;
    end;

虽然指针不是零,但我只有一条空消息。有人给我一些提示吗?

PS:我使用的是 Delphi XE4,我知道我应该使用扩展 RTTI 而不是经典,但无论如何,我不能在这两个功能中做我想要的......所以,任何帮助将不胜感激。感谢您的回复。


最终版,问题已解决:

这是基于(我朋友的帮助和......)RTTI单元(TRTTIInstanceProperty类的DoSetValue方法)的代码:

procedure ShowVirtualSettersNames(pObject: Pointer);
var
  vSetter, vPointer: Pointer;
  vPropList: TArray<TRttiProperty>;
  vProp: TRttiProperty;
begin
  vPropList:= RTTIUtils.ExtractProperties(TObject(pObject).ClassType); // Helper to get properties from a type, based in extended RTTI

  for vProp in vPropList do
  begin
    vPointer:= TRttiInstanceProperty(vProp).PropInfo^.SetProc;
    vPointer:= PPointer(PInteger(pObject)^ + Smallint(vPointer))^;    
    ShowMessage(TObject(pObject).ClassType.MethodName(vPointer));
  end;
end;

这仅适用于虚拟二传手,对于静态消息是空的。感谢大家!

4

2 回答 2

2

您可以检索此方法名称,如果

a) 将方法移动到已发布部分(经典 RTTI 仅适用于此部分(更准确 - 使用 {$M+} 指令编译))

b)使用正确的类说明符 - MyClass.MethodName,因为 MethodName 是类函数

此代码适用于 D7 和 XE3:

MyClass = class(TInterfacedPersistent)
private
  FMyProperty: Integer;
published
   procedure setMyProperty(Value: Integer);
   property MyProperty: Integer read FMyProperty write setMyProperty;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  ppi: PPropInfo;
begin
  ppi := GetPropInfo(MyClass, 'MyProperty');
  ShowMessage(MyClass.MethodName(ppi.SetProc));
end;

PS你使用的是什么Delphi版本?扩展 RTTI(自 D2010 起)怎么样?

于 2013-07-17T06:20:03.103 回答
0

c:\rad studio\9.0\source\rtl\common\System.Rtti.pas

procedure TRttiInstanceProperty.DoSetValue

属性的设置器可能是

  • 一个字段(变量)
  • 静态过程
  • 一个虚拟程序(你的情况)

而这些案例使得PropInfo^.SetProc它的价值具有不同的语义。直接地址仅适用于静态过程。对于虚拟方法,您添加一个 VMT 偏移量并从该内存单元获取代码地址,正如我提到的代码中所指定的(但出于版权原因不会引用)。

或者您可以使用TRttiProperty.SetValue并让 Delphi 完成所有这些小细节。请参阅http://docwiki.embarcadero.com/Libraries/XE2/en/System.Rtti.TRttiProperty.SetValue

编辑:

  1. 删除的代码 - 它没有逐字运行,并且主题启动器提供了工作版本。
  2. 关于并且我知道我应该使用Extended RTTI而不是classic一个- 这是有问题的说法。Extended RTTI众所周知,它的工作速度明显比经典的慢。不知道是否有人对其进行了分析,但我怀疑这主要是由于TValue. 你可以谷歌,发现很多人抱怨实施缓慢TValue,并提供了效率固定的替代方案。但是,由于Extended RTTI仅使用库存TValue,因此无法从这些实现中受益,并且仍然比经典实现慢。
于 2013-07-17T06:26:04.157 回答