4

我正在尝试使用 RTTI 向控件添加事件处理程序,该控件可能已经设置了事件处理程序。代码看起来像这样:

var
  prop: TRttiProperty;
  val: TValue;
begin
  prop := FContext.GetType(MyControl.ClassInfo).GetProperty('OnChange');
  val := prop.GetValue(MyControl);
  FOldOnChange := val.AsType<TNotifyEvent>;
  prop.SetValue(MyControl, TValue.From<TNotifyEvent>(self.MyOnChange));
end;

我想要这个,所以我可以在 MyOnChange 中执行此操作:

begin
  if assigned(FOldOnChange) then
    FOldOnChange(Sender);
  //additional code here
end;

不幸的是,编译器似乎不喜欢这条线FOldOnChange := val.AsType<TNotifyEvent>;。它说

E2010 不兼容的类型:“过程、无类型指针或无类型参数”和“TNotifyEvent”

任何人都知道这是为什么或如何解决它?在我看来是对的...

4

2 回答 2

9

FOldOnChange是方法指针类型,whileAsType<TNotifyEvent>是方法。编译器认为您正在尝试将方法分配给方法指针。解决方法是在方法调用后追加()强制,将方法的返回值作为赋值给FOldOnChange.

这是一个完整的例子:

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.
于 2010-03-11T10:14:17.830 回答
1

2010 年推出的新 RTTI 基本上只是旧 TypInfo RTTI(目前)的高级包装。在 TypInfo 中,事件处理程序由 TMethod 记录表示。试试这个(未经测试):

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;
于 2010-03-10T20:24:31.077 回答