Я могу воспроизвести это, и это явно ошибка в компараторе по умолчанию для методов.
Я подал КК # 98942 .
Вот мой код:
program TMethodComparer;
{$APPTYPE CONSOLE}
uses
SysUtils, Generics.Collections;
type
TMyMethod = procedure of object;
type
TMyClass = class
published
procedure P1;
procedure P2;
procedure P3;
end;
{ TMyClass }
procedure TMyClass.P1;
begin
end;
procedure TMyClass.P2;
begin
end;
procedure TMyClass.P3;
begin
end;
var
List: TList<TMyMethod>;
MyObject1, MyObject2: TMyClass;
begin
MyObject1 := TMyClass.Create;
MyObject2 := TMyClass.Create;
List := TList<TMyMethod>.Create;
List.Add(MyObject1.P1);
List.Add(MyObject1.P2);
List.Add(MyObject2.P1);
List.Add(MyObject2.P2);
Writeln(List.IndexOf(MyObject1.P1));
Writeln(List.IndexOf(MyObject1.P2));
Writeln(List.IndexOf(MyObject2.P1));
Writeln(List.IndexOf(MyObject2.P2));
Writeln(List.IndexOf(MyObject1.P3));
end.
выход
0
0
0
0
0
Ожидаемый результат
0
1
2
3
-1
Компаратор по умолчанию в Generics.Defaults
реализован так:
type
TMethodPointer = procedure of object;
function Compare_Method(Inst: PSimpleInstance; const Left, Right: TMethodPointer): Integer;
begin
if PInt64(@Left)^ < PInt64(@Right)^ then
Result := -1
else if PInt64(@Left)^ > PInt64(@Right)^ then
Result := 1
else
Result := 0;
end;
Я могу понять, что это пытается сделать, но с треском проваливается. Я до сих пор не могу понять, как получаются эти броски.
Я считаю, что 32-битная версия Compare_Method
должна была быть написана так:
function Compare_Method(Inst: PSimpleInstance; const Left, Right: TMethod): Integer;
begin
if Int64(Left) < Int64(Right) then
Result := -1
else if Int64(Left) > Int64(Right) then
Result := 1
else
Result := 0;
end;
И это приводит к ожидаемому результату.
Очевидно, что для 64-битной цели (т. Е. В XE2) никакой подход, основанный на совмещении с 64-битным целым числом, работать не будет.
Итак, чтобы обойти ошибку, вы можете добавить следующие функции:
function Compare_Method(const Left, Right: TMethod): Integer;
var
LCode, LData: PByte;
RCode, RData: PByte;
begin
LCode := PByte(Left.Code);
LData := PByte(Left.Data);
RCode := PByte(Right.Code);
RData := PByte(Right.Data);
if LData<RData then
Result := -1
else if LData>RData then
Result := 1
else if LCode<RCode then
Result := -1
else if LCode>RCode then
Result := 1
else
Result := 0;
end;
function CompareMyMethod(const Left, Right: TMyMethod): Integer;
begin
Result := Compare_Method(TMethod(Left), TMethod(Right))
end;
А затем создайте список следующим образом:
List := TList<TMyMethod>.Create(
TComparer<TMyMethod>.Construct(CompareMyMethod)
);