Как правильно использовать TValue.AsType <TNotifyEvent>? - PullRequest
3 голосов
/ 10 марта 2010

Я пытаюсь использовать 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 голосов
/ 11 марта 2010

FOldOnChange относится к типу указателя на метод, а AsType<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.
1 голос
/ 10 марта 2010

Новый RTTI, представленный в 2010 году, представляет собой просто расширенную оболочку для старого RTTI TypInfo (пока). В 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;
...