I have an Address class in C# that looks like this:
我在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; }
}
I'm implementing equality and so I need to override the hash code. At first I was going to use the hashcode formula from EJ but then I thought: These are all string fields, can't I just just use a StringBuilder to concatenate them and return the hash code from that string?
我正在实现相等性,所以我需要覆盖哈希码。起初我打算使用EJ的哈希码公式,但后来我想:这些都是字符串字段,我不能只使用StringBuilder连接它们并从该字符串返回哈希码吗?
That is:
var str = new StringBuilder();
str.Append(StreetAddress)
.Append(RuralRoute)
...
return str.ToString().GetHashCode();
What are the advantages/disadvantages of this? Why shouldn't I do it?
这有什么优点/缺点?我为什么不这样做?
4 个解决方案
#1
I would avoid doing that simply on the grounds that it creates a bunch of strings pointlessly - although Kosi2801's point about making collisions simple is also relevant. (I suspect it wouldn't actually create many collisions, due to the nature of the fields, but...)
我会避免这样做只是因为它毫无意义地创造了一堆字符串 - 尽管Kosi2801关于简化碰撞的观点也很重要。 (我怀疑它实际上不会产生很多碰撞,因为这些领域的性质,但......)
I would go for the "simple and easy to get right" algorithm I've previously used in this answer (thanks for looking it up lance :) - and which is listed in Effective Java, as you said. In this case it would end up as:
我会选择我之前在这个答案中使用的“简单易用”算法(感谢查找它) - 并且正如您所说的那样列在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;
}
That's not null-safe, of course. If you're using C# 3 you might want to consider an extension method:
当然,这不是无效的。如果您使用的是C#3,则可能需要考虑扩展方法:
public static int GetNullSafeHashCode<T>(this T value) where T : class
{
return value == null ? 1 : value.GetHashCode();
}
Then you can use:
然后你可以使用:
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;
}
You could create a parameter array method utility to make this even simpler:
您可以创建一个参数数组方法实用程序,以使其更简单:
public static int GetHashCode(params object[] values)
{
int hash = 17;
foreach (object value in values)
{
hash = hash * 23 + value.GetNullSafeHashCode();
}
return hash;
}
and call it with:
并称之为:
public int GetHashCode()
{
return HashHelpers.GetHashCode(StreetAddress, RuralRoute, City,
Province, Country, PostalCode);
}
In most types there are primitives involved, so that would perform boxing somewhat unnecessarily, but in this case you'd only have references. Of course, you'd end up creating an array unnecessarily, but you know what they say about premature optimization...
在大多数类型中都涉及到原语,因此在不必要的情况下执行装箱,但在这种情况下,您只有引用。当然,你最终会不必要地创建一个数组,但你知道他们对过早优化的看法......
#2
Don't do that because the objects can be different altough the hashcode is the same.
不要这样做,因为对象可以是不同的,尽管哈希码是相同的。
Think of
"StreetAddress" + "RuralRoute" + "City"
vs
"Street" + "AddressRural" + "RouteCity"
Both will have the same hashcode but different content in the fields.
两者都将具有相同的哈希码,但字段中的内容不同。
#3
For this sort of thing, you might want to implement IEqualityComparer<Address>
:
对于这种情况,您可能希望实现IEqualityComparer
: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
}
}
You could also implement IComparable<Address>
to get ordering...
你也可以实现IComparable
来获得订购......#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;
}
#1
I would avoid doing that simply on the grounds that it creates a bunch of strings pointlessly - although Kosi2801's point about making collisions simple is also relevant. (I suspect it wouldn't actually create many collisions, due to the nature of the fields, but...)
我会避免这样做只是因为它毫无意义地创造了一堆字符串 - 尽管Kosi2801关于简化碰撞的观点也很重要。 (我怀疑它实际上不会产生很多碰撞,因为这些领域的性质,但......)
I would go for the "simple and easy to get right" algorithm I've previously used in this answer (thanks for looking it up lance :) - and which is listed in Effective Java, as you said. In this case it would end up as:
我会选择我之前在这个答案中使用的“简单易用”算法(感谢查找它) - 并且正如您所说的那样列在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;
}
That's not null-safe, of course. If you're using C# 3 you might want to consider an extension method:
当然,这不是无效的。如果您使用的是C#3,则可能需要考虑扩展方法:
public static int GetNullSafeHashCode<T>(this T value) where T : class
{
return value == null ? 1 : value.GetHashCode();
}
Then you can use:
然后你可以使用:
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;
}
You could create a parameter array method utility to make this even simpler:
您可以创建一个参数数组方法实用程序,以使其更简单:
public static int GetHashCode(params object[] values)
{
int hash = 17;
foreach (object value in values)
{
hash = hash * 23 + value.GetNullSafeHashCode();
}
return hash;
}
and call it with:
并称之为:
public int GetHashCode()
{
return HashHelpers.GetHashCode(StreetAddress, RuralRoute, City,
Province, Country, PostalCode);
}
In most types there are primitives involved, so that would perform boxing somewhat unnecessarily, but in this case you'd only have references. Of course, you'd end up creating an array unnecessarily, but you know what they say about premature optimization...
在大多数类型中都涉及到原语,因此在不必要的情况下执行装箱,但在这种情况下,您只有引用。当然,你最终会不必要地创建一个数组,但你知道他们对过早优化的看法......
#2
Don't do that because the objects can be different altough the hashcode is the same.
不要这样做,因为对象可以是不同的,尽管哈希码是相同的。
Think of
"StreetAddress" + "RuralRoute" + "City"
vs
"Street" + "AddressRural" + "RouteCity"
Both will have the same hashcode but different content in the fields.
两者都将具有相同的哈希码,但字段中的内容不同。
#3
For this sort of thing, you might want to implement IEqualityComparer<Address>
:
对于这种情况,您可能希望实现IEqualityComparer
: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
}
}
You could also implement IComparable<Address>
to get ordering...
你也可以实现IComparable
来获得订购......#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;
}