2014-03-13 25 views
8

在32位和64位下编译时,TPair的默认排序似乎有区别。在32位以下,默认的排序就像它在64位的对中的键排序一样,它看起来是按值排序的。这是预期的,还是我错过了什么?使用默认排序对一个TList <TPair <整数,整数>>进行排序

测试用Delphi XE2,更新4.在一个VCL应用,下降按钮,复选框,列表框到屏幕上,声明下述类型

type TPairComparer = TComparer<TPair<integer,integer>>; 

然后将下面的代码在按钮的OnClick和运行。在32位下,使用默认排序,这些对通过键列出,即1,2,3,4,5,6。在64位下,这些对按值列出,即2,5,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])); 

end;

+2

请不要写'case of'。只需使用简单的'if'语句即可。它的方式更具可读性。 –

+0

每一个给他自己。 – Paul

回答

6

这种类型的默认比较器是非常随意的。编译器不使用关于组成记录的任何知识。你当然没有告诉它你想成为主要排序键的成员。所以它可以自由地做它想做的事情。

在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; 

底线是,你需要提供一个真正的比较器,只要你想记录进行排序。只有在数字和字符串类型中内置了定义明确的有序比较器。

+2

“只有以数字和字符串类型构建的定义良好的有序比较器才有效。”如果你曾经看过TOrdinalStringComparer.Compare,你不会那么说;) –

+0

谢谢大卫,现在有道理。这是我依赖于非重要数据的默认排序的唯一例子之一。获得的教训,始终指定一个比较器... – Paul

相关问题