How to use TValue.AsType<TNotifyEvent> properly?
I'm trying to use RTTI to add an event handler to a control, that may already have an event handler set. The code looks something like this:
var
prop: TRttiProperty;
val: TValue;
begin
prop := FContext.GetType(MyControl.ClassInfo).GetProperty('OnChange');
val := prop.GetValue(MyControl);
FOldOnChange := val.AsType<TNotif开发者_JS百科yEvent>;
prop.SetValue(MyControl, TValue.From<TNotifyEvent>(self.MyOnChange));
end;
I want this so I can do this in MyOnChange:
begin
if assigned(FOldOnChange) then
FOldOnChange(Sender);
//additional code here
end;
Unfortunately, the compiler doesn't seem to like the line FOldOnChange := val.AsType<TNotifyEvent>;
. It says
E2010 Incompatible types: 'procedure, untyped pointer or untyped parameter' and 'TNotifyEvent'
Anyone know why that is or how to fix it? It looks right to me...
FOldOnChange
is of a method pointer type, while AsType<TNotifyEvent>
is a method. The compiler thinks you're trying to assign the method to the method pointer. The solution is to append ()
to the method call to force it, and use the return value of the method as the value to assign to FOldOnChange
.
Here's a complete example:
uses SysUtils, Rtti;
type
TEv = procedure(Sender: TObject) of object;
TObj = class
private
FEv: TEv;
public
property Ev: TEv read FEv write FEv;
class procedure Meth(Sender: TObject);
end;
class procedure TObj.Meth(Sender: TObject);
begin
end;
procedure P;
var
ctx: TRttiContext;
t: TRttiType;
p: TRttiProperty;
v: TValue;
o: TObj;
e: TEv;
begin
t := ctx.GetType(TObj);
p := t.GetProperty('Ev');
o := TObj.Create;
try
// Set value explicitly
o.Ev := TObj.Meth;
// Get value via RTTI
v := p.GetValue(o);
//e := v.AsType<TEv>; // doesn't work
e := v.AsType<TEv>(); // works
finally
o.Free;
end;
end;
begin
try
P;
except
on e: Exception do
Writeln(e.Message);
end;
end.
The new RTTI introduced in 2010 is basically just an advanced wrapper around the older TypInfo RTTI (for now). In TypInfo, event handlers are represented by the TMethod record. Try this (untested):
var
prop: TRttiProperty;
val: TValue;
evt: TNotifyEvent;
begin
prop := FContext.GetType(MyControl.ClassInfo).GetProperty('OnChange');
val := prop.GetValue(MyControl);
TMethod(FOldOnChange) := val.AsType<TMethod>;
evt := Self.MyOnChange;
prop.SetValue(MyControl, TValue.From<TMethod>(TMethod(evt));
end;
精彩评论