在32位与64位下编译时,TPair的默认排序似乎存在差异.在32位下,默认排序的行为类似于在对的Key上排序,在64位下,它看起来按值排序.这是预期的,还是我错过了什么?
使用Delphi XE2进行测试,更新4.在VCL应用程序中,将按钮,复选框和列表框拖放到屏幕上,声明以下类型
type TPairComparer = TComparer<TPair<integer,integer>>;
然后将下面的代码放在OnClick按钮上并运行.在32位下,使用默认排序,按键列出对,即1,2,3,4,5,6.在64位下,这些对按值列出,即2,6,7,8,9,而不是按键.
为了使代码在两个平台上一致地工作,我需要指定我自己的比较器来强制在64位可执行文件上按键排序.
procedure TForm1.Button1Click(Sender: TObject); var PriorityList : TList<TPair<Integer,integer>>; Pair : TPair<integer,integer>; PairComparer : IComparer<TPair<integer,integer>>; iLoop : integer; begin PriorityList := TList<TPair<Integer,integer>>.Create; PairComparer := TPairComparer.Construct( function(const Left,Right: TPair<integer,integer>): Integer begin case Left.Key = Right.Key of true : Result := 0; else case Left.Key < Right.Key of true : Result := -1; else Result := +1; end; end; end); Pair.Key := 6; Pair.Value := 6; PriorityList.Add(Pair); Pair.Key := 5; Pair.Value := 5; PriorityList.Add(Pair); Pair.Key := 4; Pair.Value := 8; PriorityList.Add(Pair); Pair.Key := 3; Pair.Value := 9; PriorityList.Add(Pair); Pair.Key := 2; Pair.Value := 7; PriorityList.Add(Pair); Pair.Key := 1; Pair.Value := 2; PriorityList.Add(Pair); case CheckBox1.Checked of true : PriorityList.Sort; false : PriorityList.Sort(PairComparer); end; ListBox1.Clear; for iLoop := 0 to PriorityList.Count-1 do ListBox1.Items.Add(Format('Key : %d,Value : %d',[PriorityList[iLoop].Key,PriorityList[iLoop].Value]));
结束;
解决方法
这种类型的默认比较器非常随意.编译器不使用任何记录组成的知识.您当然没有告诉它您希望哪个成员成为主要的排序键.所以它可以自由地做它想要的东西.
在32位中,8字节记录的默认比较器是通过调用类似CompareMem的函数实现的.因此,字节按递增的地址顺序进行比较.因此关键更重要.
在64位下,默认比较器将类型视为无符号64位整数,因此字节按递减的地址顺序进行比较,这是小端.因此价值更重要.
相关代码位于Generics.Defaults的实现部分:
function Comparer_Selector_Binary(info: PTypeInfo; size: Integer): Pointer; begin case size of // NOTE: Little-endianness may cause counterintuitive results,// but the results will at least be consistent. 1: Result := @Comparer_Instance_U1; 2: Result := @Comparer_Instance_U2; 4: Result := @Comparer_Instance_U4; {$IFDEF cpuX64} // 64-bit will pass const args in registers 8: Result := @Comparer_Instance_U8; {$ENDIF} else Result := MakeInstance(@Comparer_Vtable_Binary,size); end; end;
最重要的是,只要您希望对记录进行排序,就需要提供真正的比较器.只有内置数字和字符串类型才有明确定义的有序比较器.