David đã làm một công việc tuyệt vời của bản văn mô tả như thế nào Người đối chiếu mặc định làm việc, nhưng đối với một số bạn nó có thể được dễ dàng hơn để làm theo khi bạn nhìn thấy cách mã cơ bản là có cấu trúc (và quyết định xem các trình so sánh mặc định có được áp dụng không).
Tôi sẽ chỉ bao gồm kiểu so sánh Compare_
. Kiểu dáng Equals_
hoạt động theo cách tương tự.
gì xảy ra là _LookupVtableInfo
chọn một giao diện IComparer
cho Compare_
so sánh phong cách (và một phong cách IEqualityComparer
cho Equals_
).
Bên dưới những giao diện là giao diện không bình thường, nhưng giấy gói giao diện xung quanh các chức năng toàn cầu của mẫu này cho Compare_
phong cách:
function Compare_t<T>(Inst: Pointer; const Left, Right: T): Integer;
và toàn cầu thủ tục của biểu mẫu này cho Equals_
phong cách:
function Equals_t<T>(Inst: Pointer; const Left, Right: T): Integer;
function GetHashCode_t<T>(Inst: Pointer; const Left, Right: T): Integer;
Các kết quả của các hàm phong cách Compare_
rất đơn giản, nhưng hơi khác với -1, 0, +1 mà một số người có thể mong đợi:
< 0 for Left < Right
= 0 for Left = Right
> 0 for Left > Right
Đối với đa số trường hợp, việc thực hiện rất đơn giản:
Tôi đã nhóm lại các chức năng phong cách Compare_
bởi cách họ làm điều này.
- Loại thông thường (bao gồm cả điều tra viên và Int64).
- Điểm nổi (Real) (bao gồm cả Comp và Đơn vị tiền tệ).
- Chuỗi ngắn (từ Turbo Pascal/Delphi 1 ngày).
- Chuỗi rộng (kiểu dây OLE).
- Phương pháp.
- Con trỏ (bao gồm Lớp học, Giao diện, Tham chiếu và Thủ tục của lớp).
(Loại thông thường ngoài phạm vi 1, 2, 4, 8 byte và các loại thực ngoài phạm vi 4, 8, 10 byte nêu lỗi vì chúng là bất hợp pháp).
Nhóm thứ nhất chỉ trừ trái từ bên phải: ký/số nguyên unsigned của 1 hoặc 2 byte chiều dài
function Compare_I1(Inst: Pointer; const Left, Right: Shortint): Integer;
function Compare_I2(Inst: Pointer; const Left, Right: Smallint): Integer;
function Compare_U1(Inst: Pointer; const Left, Right: Byte): Integer;
function Compare_U2(Inst: Pointer; const Left, Right: Word): Integer;
Result := Left - Right;
Nhóm thứ hai làm một so sánh:
function Compare_I4(Inst: Pointer; const Left, Right: Integer): Integer;
function Compare_I8(Inst: Pointer; const Left, Right: Int64): Integer;
function Compare_U4(Inst: Pointer; const Left, Right: LongWord): Integer;
function Compare_U8(Inst: Pointer; const Left, Right: UInt64): Integer;
function Compare_R4(Inst: Pointer; const Left, Right: Single): Integer;
function Compare_R8(Inst: Pointer; const Left, Right: Double): Integer;
function Compare_R10(Inst: Pointer; const Left, Right: Extended): Integer;
function Compare_RI8(Inst: Pointer; const Left, Right: Comp): Integer;
function Compare_RC8(Inst: Pointer; const Left, Right: Currency): Integer;
function Compare_WString(Inst: PSimpleInstance; const Left, Right: WideString): Integer;
function Compare_Pointer(Inst: PSimpleInstance; Left, Right: NativeUInt): Integer;
type
{$IFNDEF NEXTGEN}
TPS1 = string[1];
TPS2 = string[2];
TPS3 = string[3];
{$ELSE NEXTGEN}
OpenString = type string;
TPS1 = string;
TPS2 = string;
TPS3 = string;
{$ENDIF !NEXTGEN}
function Compare_PS1(Inst: PSimpleInstance; const Left, Right: TPS1): Integer;
function Compare_PS2(Inst: PSimpleInstance; const Left, Right: TPS2): Integer;
function Compare_PS3(Inst: PSimpleInstance; const Left, Right: TPS3): Integer;
// OpenString allows for any String[n], see http://my.safaribooksonline.com/book/programming/borland-delphi/1565926595/5dot-language-reference/ch05-openstring
function Compare_PSn(Inst: PSimpleInstance; const Left, Right: OpenString): Integer;
if Left < Right then
Result := -1
else if Left > Right then
Result := 1
else
Result := 0;
function Compare_Method(Inst: PSimpleInstance; const Left, Right: TMethodPointer): Integer;
var
LMethod, RMethod: TMethod;
begin
LMethod := TMethod(Left);
RMethod := TMethod(Right);
if LMethod < RMethod then
Result := -1
else if LMethod > RMethod then
Result := 1
else
Result := 0;
end;
Bây giờ chúng ta có được đến thú vị bit: các kết quả không đơn giản.
Sử dụng chuỗi CompareStr
. Nếu bạn muốn một cái gì đó khác nhau, bạn có thể sử dụng TOrdinalIStringComparer
function Compare_LString(Inst: PSimpleInstance; const Left, Right: AnsiString): Integer;
function Compare_UString(Inst: PSimpleInstance; const Left, Right: UnicodeString): Integer;
Result := CompareStr(Left, Right);
BinaryCompare
được sử dụng cho:
- dữ liệu nhị phân trong đó không rõ, Char/WCHAR, Set, Array, Record. Ngoại lệ nếu dữ liệu nhị phân là 1, 2 hoặc 4 byte kích thước trong x86 và x64 và 8 byte trong x64, nó sẽ được so sánh dưới dạng số nguyên.
- carrays động (hãy cẩn thận khi chúng là đa chiều!).
- biến thể như một phương sách cuối cùng (xem thêm bên dưới)
Đối với hồ sơ mà có thể được so sánh, nó làm cho tinh thần để thực hiện hành quá tải, và có Comparer sử dụng những nhà khai thác.
Dữ liệu nhị phân trong tổng số 1, 2, 4 hoặc 8 byte là một ngoại lệ, mà sẽ cho kết quả kỳ lạ trên máy ít về cuối nhỏ (Intel x86 và x64, và Arm bi-endian trong chế độ ít về cuối nhỏ):
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;
phần còn lại là nhị phân tinh khiết:
function Compare_Binary(Inst: PSimpleInstance; const Left, Right): Integer;
begin
Result := BinaryCompare(@Left, @Right, Inst^.Size);
end;
function Compare_DynArray(Inst: PSimpleInstance; Left, Right: Pointer): NativeInt;
var
len, lenDiff: NativeInt;
begin
len := DynLen(Left);
lenDiff := len - DynLen(Right);
if lenDiff < 0 then
Inc(len, lenDiff);
Result := BinaryCompare(Left, Right, Inst^.Size * len);
if Result = 0 then
Result := lenDiff;
end;
Như thường lệ, Variants
đang ở trong một giải đấu của riêng mình. Đầu tiên, VarCompareValue
đã được thử. Nếu không thành công thì Compare_UString
sẽ được thử. Nếu điều đó không thành công, BinaryCompare
sẽ được thử. Nếu điều đó thất bại: may mắn khó khăn.
function Compare_Variant(Inst: PSimpleInstance; Left, Right: Pointer): Integer;
var
l, r: Variant;
lAsString, rAsString: string;
begin
Result := 0; // Avoid warning.
l := PVariant(Left)^;
r := PVariant(Right)^;
try
case VarCompareValue(l, r) of
vrEqual: Exit(0);
vrLessThan: Exit(-1);
vrGreaterThan: Exit(1);
vrNotEqual:
begin
if VarIsEmpty(L) or VarIsNull(L) then
Exit(1)
else
Exit(-1);
end;
end;
except // if comparison failed with exception, compare as string.
try
lAsString := PVariant(Left)^;
rAsString := PVariant(Right)^;
Result := Compare_UString(nil, lAsString, rAsString);
except // if comparison fails again, compare bytes.
Result := BinaryCompare(Left, Right, SizeOf(Variant));
end;
end;
end;
FYI, bạn không có câu trả lời cho đến bây giờ vì bạn không sử dụng thẻ delphi. Thẻ phiên bản cụ thể phải luôn được sử dụng cùng với thẻ delphi chung. Cảm ơn bạn đã đến @SirRufo để tìm câu hỏi và gắn thẻ lại. –
Vâng, điều này là nhận được một chút meta, nhưng tôi sẽ chỉ nói rằng câu hỏi delphi cuối cùng tôi đăng được gắn thẻ với thẻ delphi, nhưng một người dùng với danh tiếng cực cao đã quyết định rằng không đúng, loại bỏ nó và gắn thẻ nó delphi -xe2 (và tất nhiên đã xóa thẻ delphi của tôi) mặc dù tôi đã tuyên bố rõ ràng trong câu hỏi rằng mặc dù tôi đã sử dụng XE2, nó có thể không liên quan đến câu hỏi. Tôi đã cố gắng tránh nó trước khi emptively nhưng bây giờ tôi có thể thấy rằng mọi người dường như có những cách yêu thích riêng của họ về "giúp đỡ" câu hỏi. Tôi rất vui vì điều này thực sự đã giúp, mặc dù! – jep
Tôi nghĩ rằng người dùng không hiểu các sắc thái của việc gắn thẻ delphi.Trong mọi trường hợp, câu hỏi đó dường như không phải là một câu hỏi cụ thể của delphi vì vậy tôi nghĩ rằng các thẻ ban đầu của bạn là tốt. Ở đây, đó là tất cả về Delphi và bạn cần thẻ chung. Câu hỏi này cũng được gắn thẻ, ngoài việc phân loại và so sánh cần được loại bỏ. Họ không phục vụ mục đích hữu ích. –