Как сравнить событие и соответствующую ему процедуру, избегая E2035 и E2036?

Я пытаюсь проверить, было ли уже назначено событие (TNotifyEvent) с определенным procedure(Sender: TObject) of object.

Вот мой пример кода:

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if(Button1.OnClick = Button1Click) then
  begin
    //...
  end;
end;

В этом случае я получаю следующее сообщение об ошибке:

[Ошибка DCC] Unit1.pas(28): E2035 Недостаточно фактических параметров

Итак, я пробовал следующим образом:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if(@Button1.OnClick = @Button1Click) then
  begin
    //...
  end;
end;

При компиляции ошибка меняется на:

[Ошибка DCC] Unit1.pas(28): E2036 Требуется переменная

Как я могу проверить, указывает ли Button1.OnClick на Button1Click?


person Fabrizio    schedule 13.02.2019    source источник


Ответы (1)


... of object процедуры/функции реализованы в виде замыканий, которые содержат 2 указателя — указатель на неявный параметр Self и указатель на саму процедуру/функцию. Вы можете использовать запись TMethod, чтобы получить доступ к этим указателям и сравнить их напрямую:

procedure TForm1.Button1Click(Sender: TObject);
var
  oc1, oc2: TNotifyEvent;
begin
  oc1 := Button1.OnClick;
  oc2 := Button1Click;
  if (TMethod(oc1).Data = TMethod(oc2).Data) and
     (TMethod(oc1).Code = TMethod(oc2).Code) then
  begin
    //...
  end;
end;
person Remy Lebeau    schedule 13.02.2019
comment
Поскольку TMethod является записью, нельзя ли просто использовать if TMethod(oc1) = TMethod(oc2) then ? - person Dsm; 13.02.2019
comment
Сравнение записей TMethod с оператором равенства = поддерживается начиная с XE3, когда перегруженные операторы добавляются к TMethod. - person Remy Lebeau; 13.02.2019