代码之家  ›  专栏  ›  技术社区  ›  Mason Wheeler

如何正确使用tValue.asType<tnotifyevent>?

  •  3
  • Mason Wheeler  · 技术社区  · 15 年前

    我正在尝试使用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'

    有人知道为什么或者怎么解决吗?在我看来…

    2 回复  |  直到 6 年前
        1
  •  6
  •   Barry Kelly    15 年前

    FOldOnChange 是方法指针类型,而 AsType<TNotifyEvent> 是一种方法。编译器认为您正在尝试将方法分配给方法指针。解决方案是附加 () 对方法调用进行强制,并使用方法的返回值作为要分配给的值 福利交换 .

    下面是一个完整的示例:

    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.
    
        2
  •  1
  •   Remy Lebeau    15 年前

    2010年引入的新rtti基本上只是旧typenfortti(目前)的高级包装。在typenfo中,事件处理程序由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;