如何检查两个方法引用是否引用相同的方法?

And*_*tyn 17 delphi anonymous-methods method-reference

我正在尝试制作事件处理程序列表,其中handler是方法引用.要删除特定的处理程序,我需要在列表中找到它.但是我如何比较两个方法引用的代码地址?

type
  TEventHandler = reference to procedure;

procedure TestProc;
begin
end;

procedure TForm26.FormCreate(Sender: TObject);
var
  Handlers: TList<TEventHandler>;
begin
  Handlers := TList<TEventHandler>.create;
  try
    Handlers.Add(TestProc);
    Handlers.Remove(TestProc); { doesn't work }
    Assert(Handlers.Count=0);  { fails }
    Assert(Handlers.IndexOf(TestProc)>=0); { fails }
  finally
    FreeAndNil(Handlers);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

TList <>的默认比较器不能正确比较方法引用.我该如何比较它们?是否存在类似于TMethod的结构,但是方法参考?

Ste*_*nke 15

这并不像看起来那么容易.

要理解为什么会发生这种情况,您需要了解编译器如何分配方法引用.

您编写的代码基本上由编译器翻译成:

Handlers.Add(procedure begin TestProc; end);
Handlers.Remove(procedure begin TestProc; end);
Run Code Online (Sandbox Code Playgroud)

现在我们必须知道,如果在同一例程中有多个匿名方法,即使它们的代码相同,它们实际上也是不同的匿名方法.(请参阅如何在引擎盖下实施匿名方法?)

这意味着,传递给值AddRemove不同,即使在他们的身体码是相同的-甚至与它周围的黑客将需要一个二进制代码分析,以确定体内的代码是一样的.

如果您将如下更改代码,它将起作用,因为那时您只有一个匿名方法 - 对于此剪切它可以工作但通常您不会在完全相同的例程中添加和删除:

var
  Handlers: TList<TEventHandler>;
  Handler: TEventHandler;
begin
  Handlers := TList<TEventHandler>.create;
  try
    Handler := TestProc;
    Handlers.Add(Handler);
    Handlers.Remove(Handler);
    Assert(Handlers.Count=0);
  finally
    FreeAndNil(Handlers);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

如果你想要一个添加和删除事件处理程序的列表,我的个人建议是避免匿名方法类型和使用过程或方法:

type
  TEventHandlerA = procedure;
  TEventHandlerB = procedure of object;
Run Code Online (Sandbox Code Playgroud)

决定哪一个更好取决于你,因为你更了解你的代码.