Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if two method references are referencing same method?

I am trying to make list of event handlers where handler is method reference. To delete specific handler i need to find it in the list. But how can i compare code address of two method references?

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;

Default comparer of TList<> doesn't compare method references properly. How can i compare them? Is there structure similar to TMethod but for method references?

like image 318
Andrei Galatyn Avatar asked Oct 26 '16 11:10

Andrei Galatyn


People also ask

What is a method reference with different types?

There are four kinds of method references: Static methods. Instance methods of particular objects. Instance methods of an arbitrary object of a particular type.

What is Java 8 method reference?

Java provides a new feature called method reference in Java 8. Method reference is used to refer method of functional interface. It is compact and easy form of lambda expression. Each time when you are using lambda expression to just referring a method, you can replace your lambda expression with method reference.

What is static method reference in Java?

A static method reference refers to a static method in a specific class. Its syntax is className::staticMethodName , where className identifies the class and staticMethodName identifies the static method. An example is Integer::bitCount .


1 Answers

This is not as easy as it might seem.

To understand why this happens you need to understand how assigning to a method reference is performed by the compiler.

The code you wrote is basically translated into this by the compiler:

Handlers.Add(procedure begin TestProc; end);
Handlers.Remove(procedure begin TestProc; end);

Now we have to know that if you have multiple anonymous methods within the same routine they are in fact different anonymous methods even if their code is identical. (see How are anonymous methods implemented under the hood?)

This means that the values passed to Add and Remove are different even if the code in their bodies is the same - even with hacking around it would require a binary code analysis to determine if the code inside the body is the same.

If you would change the code as follows it would work because then you only have one anonymous method - for this snipped it works but usually you would not add and remove within the exact same routine:

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;

If you want a list where you add and remove event handlers my personal recommendation is to avoid an anonymous method type and use procedure or methods:

type
  TEventHandlerA = procedure;
  TEventHandlerB = procedure of object;

The decision which one is better is up to you because you know your code better.

like image 93
Stefan Glienke Avatar answered Oct 23 '22 08:10

Stefan Glienke