You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何含String字段的记录默认相等比较器在列表索引访问时行为异常?

关于TEqualityComparer.Default处理含String字段记录的相等性问题分析

当使用TEqualityComparer<T>.Default处理包含String字段的记录类型时,会出现不一致的相等性检查结果:直接比较两个记录实例返回true,但从数组/列表中通过索引取出实例后再比较却返回false;如果记录不含String这类托管类型则无此问题。以下是复现代码:

type
  TestRec = record
    Value: String;
  end;
begin
  var Rec1: TestRec;
  var Rec2: TestRec;
  Rec1.Value := 'a';
  Rec2.Value := 'a';

  var List1: TArray<TestRec> := [Rec1];
  var List2: TArray<TestRec> := [Rec2];

  var Comparer: IEqualityComparer<TestRec>;
  Comparer := TEqualityComparer<TestRec>.Default;

  Comparer.Equals(Rec1, Rec2); // 返回true
  Comparer.Equals(List1[0], List2[0]); // 返回false
end;

核心原因:默认比较器的内存逐字节比较逻辑

TEqualityComparer<T>.Default对于未实现IEquatable<T>的记录类型,默认采用**内存逐字节比较(CompareMem)**来判断相等性,而非递归检查每个字段的逻辑相等性:

  • 直接比较记录实例时:Delphi的字符串采用引用计数机制,相同字面量会复用内存实例,因此Rec1.Value和Rec2.Value指向同一个内存地址。此时两个记录的内存布局完全一致,CompareMem返回true。
  • 从数组中取出实例比较时:记录存入数组会触发值拷贝。尽管字符串内容相同,但在某些场景下(如编译器优化差异、内存分配时机不同),数组中记录的字符串指针可能指向不同的内存地址。此时两个记录的内存布局中,字符串指针的字节内容不一致,CompareMem逐字节对比后返回false。

非托管类型无此问题的原因

对于整数、布尔值这类非托管值类型,它们的内存直接存储实际值而非引用指针。无论是否存入数组,值拷贝后的内存内容完全一致,因此CompareMem能正确判断相等性。

补充:最优解决方案

实现IEquatable<TestRec>接口,在Equals方法中手动比较每个字段的逻辑相等性(比如直接对比Value字符串的内容),即可彻底避免内存比较带来的不一致问题。

内容的提问来源于stack exchange,提问作者easely

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:55:11