加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 方法的默认通用比较器返回不正确的结果

发布时间:2020-12-15 04:17:00 所属栏目:大数据 来源:网络整理
导读:在使用建议的 multicast delegate方法来响应 Signals and slots implementation in Delphi问题时,代码无法添加多个事件处理程序. 问题与在TDelegateImpl T .Add()中向事件列表添加方法有关,TList T .IndexOf方法使用Compare方法查找现有方法,结果始终为0 –
在使用建议的 multicast delegate方法来响应 Signals and slots implementation in Delphi问题时,代码无法添加多个事件处理程序.

问题与在TDelegateImpl< T> .Add()中向事件列表添加方法有关,TList< T> .IndexOf方法使用Compare方法查找现有方法,结果始终为0 – 表示Left和Right是同样适用于TMethod. Equals方法使用TMethod类型转换并显式比较TMethod.Code和TMethod.Data,其中Compare转换为始终相同的地址.

为什么在TList< T> .IndexOf中使用Compare而不是Equals?

解决方法

问题是这个功能:
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;

这将方法与Int64进行比较.这不起作用,因为@可能在这里没有效果.

CPU视图确认了这一点:

System.Generics.Defaults.pas.1089: begin
00447690 55               push ebp
00447691 8BEC             mov ebp,esp
System.Generics.Defaults.pas.1090: if PInt64(@Left)^ < PInt64(@Right)^ then
00447693 8B4510           mov eax,[ebp+$10]
00447696 8B5004           mov edx,[eax+$04]
00447699 8B00             mov eax,[eax]
0044769B 8B4D08           mov ecx,[ebp+$08]
0044769E 3B5104           cmp edx,[ecx+$04]
004476A1 7506             jnz $004476a9
004476A3 3B01             cmp eax,[ecx]
004476A5 7309             jnb $004476b0
004476A7 EB02             jmp $004476ab
004476A9 7D05             jnl $004476b0
System.Generics.Defaults.pas.1091: Result := -1
004476AB 83C8FF           or eax,-$01
004476AE EB21             jmp $004476d1
System.Generics.Defaults.pas.1092: else if PInt64(@Left)^ > PInt64(@Right)^ then
004476B0 8B4510           mov eax,[ebp+$10]
etc...

要将两个TM方法作为Int64进行比较,这应该是:

System.Generics.Defaults.pas.1090: if PInt64(@Left)^ < PInt64(@Right)^ then
00447693 8B4510           lea eax,[ebp+$10] // not MOV
00447696 8B5004           mov edx,[eax]
0044769B 8B4D08           lea ecx,[ebp+$08] // not MOV
0044769E 3B5104           cmp edx,[ecx]
etc...

这清楚地表明PInt64(@Left)^被解释为PInt64(左)^.

对于Delphi 32和Delphi 64,正确的实现应该或多或少看起来像这样:

function Compare_Method(Inst: PSimpleInstance; const Left,Right: TMethodPointer): Integer;
var
  LCode,LData: PByte;
  RCode,RData: PByte;
begin
  LCode := PByte(TMethod(Left).Code);
  LData := PByte(TMethod(Left).Data);
  RCode := PByte(TMethod(Right).Code);
  RData := PByte(TMethod(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;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读