如何检查两个方法引用是否引用相同的方法?
How to check if two method references are referencing same method?
我正在尝试制作事件处理程序列表,其中处理程序是方法引用。
要删除特定的处理程序,我需要在列表中找到它。
但是如何比较两个方法引用的代码地址呢?
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;
TList<> 的默认比较器未正确比较方法引用。
我如何比较它们?是否有类似于TMethod的结构,但用于方法引用?
这并不像看起来那么容易。
要理解为什么会发生这种情况,您需要了解编译器如何执行对方法引用的赋值。
你写的代码基本上编译器翻译成这样:
Handlers.Add(procedure begin TestProc; end);
Handlers.Remove(procedure begin TestProc; end);
现在我们必须知道,如果您在同一个例程中有多个匿名方法,即使它们的代码相同,它们实际上也是不同的匿名方法。 (参见 )
这意味着传递给 Add
和 Remove
的值是不同的,即使它们体内的代码是相同的——即使绕过它也需要二进制代码分析来确定是否body里面的代码是一样的
如果您按如下方式更改代码,它会起作用,因为那样您只有一个匿名方法 - 对于这个片段它可以起作用,但通常您不会在完全相同的例程中添加和删除:
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;
如果您想要一个添加和删除事件处理程序的列表,我个人的建议是避免使用匿名方法类型并使用过程或方法:
type
TEventHandlerA = procedure;
TEventHandlerB = procedure of object;
哪个更好取决于您,因为您更了解您的代码。
我正在尝试制作事件处理程序列表,其中处理程序是方法引用。 要删除特定的处理程序,我需要在列表中找到它。 但是如何比较两个方法引用的代码地址呢?
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;
TList<> 的默认比较器未正确比较方法引用。 我如何比较它们?是否有类似于TMethod的结构,但用于方法引用?
这并不像看起来那么容易。
要理解为什么会发生这种情况,您需要了解编译器如何执行对方法引用的赋值。
你写的代码基本上编译器翻译成这样:
Handlers.Add(procedure begin TestProc; end);
Handlers.Remove(procedure begin TestProc; end);
现在我们必须知道,如果您在同一个例程中有多个匿名方法,即使它们的代码相同,它们实际上也是不同的匿名方法。 (参见
这意味着传递给 Add
和 Remove
的值是不同的,即使它们体内的代码是相同的——即使绕过它也需要二进制代码分析来确定是否body里面的代码是一样的
如果您按如下方式更改代码,它会起作用,因为那样您只有一个匿名方法 - 对于这个片段它可以起作用,但通常您不会在完全相同的例程中添加和删除:
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;
如果您想要一个添加和删除事件处理程序的列表,我个人的建议是避免使用匿名方法类型并使用过程或方法:
type
TEventHandlerA = procedure;
TEventHandlerB = procedure of object;
哪个更好取决于您,因为您更了解您的代码。