Reputation: 304
In the following type:
MyClass = class(TInterfacedPersistent)
private
FMyProperty: Integer;
published
procedure setMyProperty(Value: Integer); virtual;
property MyProperty: Integer read FMyProperty write setMyProperty;
I would like to know the name of the setter method of the "MyProperty" property via RTTI. I've tried the following:
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;
Although the pointer is not nil, all I have is an empty message. Does anybody have some tip to me?
P.S.: I'm using Delphi XE4, and I know I should use extended RTTI instead of classic, but anyway, I can't do what I want in both features... So, any help will be appreciated. Thanks for the replies.
FINAL EDITION, problem solved:
Here is the code working, based in the (help of my friends and...) RTTI unit (DoSetValue method of TRTTIInstanceProperty class):
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;
This ONLY WORKS FOR VIRTUAL SETTERS, for statics the message is empty. Thanks everyone!
Upvotes: 8
Views: 3421
Reputation: 16065
Read c:\rad studio\9.0\source\rtl\common\System.Rtti.pas
procedure TRttiInstanceProperty.DoSetValue
The setter of the property may be
And those cases make PropInfo^.SetProc
have different semantics of its value.
Direct address only applies to static procedures. For virtual methods you add a VMT offset and take the code address from that memory cell, as specified in that code i mentioned (but would not quote for copyright reasons).
Or you just could use TRttiProperty.SetValue
and let Delphi do all those little under the hood details. See http://docwiki.embarcadero.com/Libraries/XE2/en/System.Rtti.TRttiProperty.SetValue
EDIT:
Extended RTTI
instead of classic
one - that is questionable claim. Extended RTTI
is known to work noticeably slower than classic one. Dunno if someone did profiled it, but i suspect that is mostly due to the slow code of TValue
. You can google and find that lot of people complained of slow TValue
implementation and provided alternative ones with fixed efficiency. However since Extended RTTI
only uses stock TValue
it cannot benefit from those implementations and remains slower than classic one.Upvotes: 0
Reputation: 80327
You can retrieve this method name, if
a) move the method to the published section (classic RTTI works with this section only (more accurately - compiled with {$M+} directive))
b) use right class specifier - MyClass.MethodName, because MethodName is class function
This code works on D7 and 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. What Delphi version are you using? What about Extended RTTI (since D2010)?
Upvotes: 2