2009-10-23 22 views
9

Tôi có một trường hợp sử dụng TDictionary:Làm thế nào để tạo ra một trường hợp TEqualityComparer nhạy cảm cho TDictionary?

var D: TDictionary<string, integer>; 
begin 
    D := TDictionary<string, integer>.Create(TCustomEqualityComparer.Create()); 
    try 
    D.Add('One', 1); 
    D.Add('Two', 2); 
    D.Add('Three', 3); 

    showmessage(inttostr(D.Items['One'])); 
    showmessage(inttostr(D.Items['TWO'])); 
    finally 
    D.Free; 
    end; 
end; 

Lớp TCustomEqualityComparer được sao chép từ Generics Defaults TEqualityComparer (Delphi) với sự sửa đổi nhỏ về phương pháp GetHashCode:

TCustomEqualityComparer = class(TEqualityComparer<string>) 
public 
    function Equals(const Left, Right: string): Boolean; override; 
    function GetHashCode(const Value: string): Integer; override; 
end; 

function TCustomEqualityComparer.Equals(const Left, Right: string): Boolean; 
begin 
    Result := SameText(Left, Right); 
end; 

function TCustomEqualityComparer.GetHashCode(const Value: string): Integer; 
begin 
    Result := BobJenkinsHash(Value[1], Length(Value) * SizeOf(Value[1]), 0); 
end; 

tôi hy vọng các TCustomEqualityComparer thể thực hiện phù hợp với case-insensitive cho giá trị khóa. Ví dụ:

D.Items['TWO'] 

Tuy nhiên, tôi nhận được ngoại lệ "Không tìm thấy mục". Tôi đang sử dụng Delphi 2010 Phiên bản 14.0.3513.24210.

Có ai biết mã của tôi có vấn đề gì không?

Trả lời

2

Cảm ơn. Tôi đã thay đổi TCustomEqualityComparer.GetHashCode và nó hoạt động như bạn nói:

function TCustomEqualityComparer.Equals(const Left, Right: string): Boolean; 
begin 
    Result := SameText(Left, Right); 
end; 

function TCustomEqualityComparer.GetHashCode(const Value: string): Integer; 
var s: string; 
begin 
    s := UpperCase(Value); 
    Result := BobJenkinsHash(s[1], Length(s) * SizeOf(s[1]), 0); 
end; 
3

HashCode phải giống nhau cho tất cả các giá trị trả về Equals = true! Hãy thử làm cho giá trị chữ hoa trong GetHashCode trước khi gửi nó đến HashFunction của bạn.

+0

Bạn có chắc chắn bản gốc Bằng đã là case-insensitive? Đây là phương thức Equals gốc được xác định trong đơn vị Generics.Defaults.pas: function Equals_UString (Inst: PSimpleInstance; const Left, Right: UnicodeString): Boolean; bắt đầu Kết quả: = Trái = Phải; kết thúc; –

+0

Bạn đã đúng! Tôi trộn lẫn thực hiện ban đầu và một ví dụ. –

12
uses System.Generics.Collections, System.Generics.Defaults; 

var 
    D: TDictionary<string, Integer>; 
begin 
    D := TDictionary<string, Integer>.Create(TIStringComparer.Ordinal); // ‹- this is the trick 
    try 
    D.Add('One', 1); 
    . 
    . 
    finally 
    D.Free; 
    end; 
end; 
Các vấn đề liên quan