我应该使用字符串字段的串联作为哈希码吗?

我在C#中有一个Address类,如下所示:

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

我正在实现相等性,所以我需要覆盖哈希码。 起初我打算使用EJ的哈希码公式,但后来我想:这些都是字符串字段,我不能只使用StringBuilder连接它们并从该字符串返回哈希码吗?

那是:

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

这有什么优点/缺点? 我为什么不这样做?

我会避免这样做只是因为它毫无意义地创造了一堆字符串 – 尽管Kosi2801关于简化碰撞的观点也很重要。 (我怀疑它实际上不会产生很多碰撞,因为这些领域的性质,但……)

我会选择我之前在这个答案中使用的“简单易用”算法(感谢查找它) – 并且正如您所说的那样列在Effective Java中。 在这种情况下,它最终会:

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

当然,这不是无效的。 如果您使用的是C#3,则可能需要考虑扩展方法:

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

然后你可以使用:

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

可以创建一个参数数组方法实用程序,以使其更简单:

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

并称之为:

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

在大多数类型中都涉及到原语,因此在不必要的情况下执行装箱,但在这种情况下,您只有引用。 当然,你最终会不必要地创建一个数组,但你知道他们对过早优化的看法……

不要这样做,因为对象可以是不同的,尽管哈希码是相同的。

考虑到

 "StreetAddress" + "RuralRoute" + "City" 

VS

 "Street" + "AddressRural" + "RouteCity" 

两者都将具有相同的哈希码,但字段中的内容不同。

对于这种情况,您可能希望实现IEqualityComparer

 public class Address : IEqualityComparer
{ // // member declarations // bool IEqualityComparer
.Equals(Address x, Address y) { // implementation here } int IEqualityComparer
.GetHashCode(Item obj) { // implementation here } }

你也可以实现IComparable

来获得订购……

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