Delphi - 提取setter方法的属性名称

时间:2013-07-17 02:45:53

标签: delphi reflection rtti delphi-xe4

以下类型:

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;

虽然指针不是nil,但我只有一条空信息。有人给我一些小费吗?

P.S。:我正在使用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;

这仅适用于虚拟设置,对于静态信息,该消息为空。谢谢大家!

2 个答案:

答案 0 :(得分: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;

P.S。您使用的是什么Delphi版本?那么 Extended RTTI (自D2010起)?

答案 1 :(得分:0)

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

procedure TRttiInstanceProperty.DoSetValue

属性的setter可能是

  • 字段(变量)
  • 静态程序
  • 虚拟程序(您的情况)

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

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

编辑:

  1. 删除了代码 - 它没有逐字处理,主题启动器提供了工作版本。
  2. 关于,我知道我应该使用Extended RTTI而不是classic一个 - 这是一个值得怀疑的说法。众所周知,Extended RTTI的工作速度明显慢于经典速度。 Dunno如果有人对它进行了描述,但我怀疑这主要是由于TValue的代码慢。您可以谷歌并发现很多人抱怨慢TValue实施,并提供具有固定效率的替代品。但是,由于Extended RTTI仅使用股票TValue,因此无法从这些实施中受益,并且仍然比经典版本慢。