2009-06-05 25 views
13

Tôi có một lớp Địa chỉ trong C# trông như thế này:Tôi có nên sử dụng kết nối các trường chuỗi của tôi dưới dạng mã băm không?

public class Address 
{    
    public string StreetAddress { get; set; } 
    public string RuralRoute { get; set; } 
    public string City { get; set; } 
    public string Province { get; set; } 
    public string Country { get; set; } 
    public string PostalCode { get; set; } 
} 

Tôi đang thực hiện bình đẳng và vì vậy tôi cần phải ghi đè mã băm. Lúc đầu, tôi sẽ sử dụng công thức hashcode từ EJ nhưng sau đó tôi nghĩ: Đây là tất cả các trường chuỗi, tôi không thể chỉ sử dụng một StringBuilder để nối chúng lại và trả về mã băm từ chuỗi đó?

Đó là:

var str = new StringBuilder(); 
str.Append(StreetAddress) 
    .Append(RuralRoute) 
    ... 

return str.ToString().GetHashCode(); 

gì là ưu điểm/nhược điểm của điều này? Tại sao tôi không nên làm điều đó?

+1

Đối với xét của bạn: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-systemobjectgethashcode – lance

Trả lời

14

Tôi sẽ tránh làm điều đó đơn giản với lý do nó tạo ra một loạt các chuỗi vô nghĩa - mặc dù điểm của Kosi2801 về việc tạo ra các va chạm đơn giản cũng có liên quan. (Tôi nghi ngờ nó sẽ không thực sự tạo ra nhiều va chạm, do bản chất của các lĩnh vực, nhưng ...)

Tôi sẽ đi cho thuật toán "đơn giản và dễ dàng để có được" tôi trước đây used in this answer (cảm ơn vì đã tìm kiếm nó :) - và được liệt kê trong Java hiệu quả, như bạn đã nói. Trong trường hợp này, nó sẽ kết thúc là:

public int GetHashCode() 
{ 
    int hash = 17; 
    // Suitable nullity checks etc, of course :) 
    hash = hash * 23 + StreetAddress.GetHashCode(); 
    hash = hash * 23 + RuralRoute.GetHashCode(); 
    hash = hash * 23 + City.GetHashCode(); 
    hash = hash * 23 + Province.GetHashCode(); 
    hash = hash * 23 + Country.GetHashCode(); 
    hash = hash * 23 + PostalCode.GetHashCode(); 
    return hash; 
} 

Đó không phải là không an toàn, tất nhiên. Nếu bạn đang sử dụng C# 3 bạn có thể muốn xem xét một phương pháp khuyến nông:

public static int GetNullSafeHashCode<T>(this T value) where T : class 
{ 
    return value == null ? 1 : value.GetHashCode(); 
} 

Sau đó, bạn có thể sử dụng:

public int GetHashCode() 
{ 
    int hash = 17; 
    // Suitable nullity checks etc, of course :) 
    hash = hash * 23 + StreetAddress.GetNullSafeHashCode(); 
    hash = hash * 23 + RuralRoute.GetNullSafeHashCode(); 
    hash = hash * 23 + City.GetNullSafeHashCode(); 
    hash = hash * 23 + Province.GetNullSafeHashCode(); 
    hash = hash * 23 + Country.GetNullSafeHashCode(); 
    hash = hash * 23 + PostalCode.GetNullSafeHashCode(); 
    return hash; 
} 

Bạn thể tạo một tiện ích thông số phương pháp mảng để làm điều này thậm chí còn đơn giản hơn :

public static int GetHashCode(params object[] values) 
{ 
    int hash = 17; 
    foreach (object value in values) 
    { 
     hash = hash * 23 + value.GetNullSafeHashCode(); 
    } 
    return hash; 
} 

và gọi nó với:

public int GetHashCode() 
{ 
    return HashHelpers.GetHashCode(StreetAddress, RuralRoute, City, 
            Province, Country, PostalCode); 
} 

Trong hầu hết các loại có nguyên thủy liên quan, do đó sẽ thực hiện quyền anh phần nào không cần thiết, nhưng trong trường hợp này bạn chỉ có tham chiếu. Tất nhiên, bạn muốn kết thúc việc tạo một mảng không cần thiết, nhưng bạn biết những gì họ nói về tối ưu hóa sớm ...

+1

Một giải pháp khác là sử dụng EqualityComparer . Default.GetHashCode (someValue). Đây là một cơ chế băm an toàn không có sẵn và nằm trong khuôn khổ từ 2.0 – JaredPar

+0

Cảm ơn, điều đó hoạt động hoàn hảo. Có một lỗi nhỏ trong phương thức GetNullSafeHashCode() của bạn: nó thiếu "this". – cdmckay

+0

Doh! Cảm ơn rất nhiều. Đã sửa. –

5

Đừng làm điều đó vì các đối tượng có thể khác nhau, độ dài mã băm giống nhau.

Hãy suy nghĩ về

"StreetAddress" + "RuralRoute" + "City" 

vs

"Street" + "AddressRural" + "RouteCity" 

Cả hai sẽ có hashcode cùng nhưng nội dung khác nhau trong các lĩnh vực.

+0

Đó là một điểm tốt, tôi đã thậm chí không xem xét điều đó. Mặc dù nó dường như không xảy ra trong thực tế. – cdmckay

+1

Coulnd't dễ dàng được giải quyết bằng cách đặt một dấu phân cách giữa các lĩnh vực? (Ví dụ: "StreetAddress" + "/ delimiter /" + "RuralRoute" + "/ delimiter /" + "City" '. Có thể là một biến để tránh nhiều bài tập trong một số ngôn ngữ?) – simonra

0

Đối với các loại điều này, bạn có thể muốn thực hiện IEqualityComparer<Address>:

public class Address : IEqualityComparer<Address> 
{   
    // 
    // member declarations 
    // 

    bool IEqualityComparer<Address>.Equals(Address x, Address y) 
    { 
     // implementation here 
    } 

    int IEqualityComparer<Address>.GetHashCode(Item obj) 
    { 
     // implementation here 
    } 
} 

Bạn cũng có thể triển khai IComparable<Address> để yêu cầu ...

-4
public string getfourDigitEncryptedText(string input) { 
    int hashCode = input.hashCode(); 
    string hstring = (new StringBuilder()).append(hashCode).append("").toString(); 
    string rev_hstring = (new StringBuilder(hstring)).reverse().toString(); 
    string parts[] = rev_hstring.trim().split(""); 
    int prefixint = 0; 
    for(int i = 1; i <= parts.length - 3; i++) 
     prefixint += integer.parseInt(parts[i]); 
    string prefixstr = "0"; 
    if((new integer(prefixint)).toString().length() < 2) 
     prefixstr = (new StringBuilder()).append((new integer(prefixint)).toString()).append("5").toString(); 
    else if((new integer(prefixint)).toString().length() > 2) 
     prefixstr = "79"; 
    else 
     prefixstr = (new integer(prefixint)).toString(); 
    string finalstr = (new StringBuilder()).append(prefixint).append(rev_hstring.substring(3, 5)).toString(); 
    return finalstr; 
} 
+0

Bạn có thể cung cấp giải thích về mã của bạn không? – DeanOC

Các vấn đề liên quan