我在C#中有一个结构:
public struct UserInfo { public string str1 { get; set; } public string str2 { get; set; } }
唯一的规则是 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))
如何覆盖此结构的GetHashCode函数?
MSDN:
哈希函数必须具有以下属性:
如果两个对象比较相等,则
GetHashCode
每个对象的方法必须返回相同的值.但是,如果两个对象的比较不相等,则两个对象的GetHashCode
方法不必返回不同的值.的
GetHashCode
用于一个对象的方法,必须一致,只要没有修改,用于确定对象的的返回值的对象的状态返回相同的散列码Equals
方法.请注意,这仅适用于当前应用程序的执行,并且如果再次运行应用程序,则可以返回不同的哈希代码.为获得最佳性能,哈希函数必须为所有输入生成随机分布.
考虑到正确的方法是:
return str1.GetHashCode() ^ str2.GetHashCode()
^
可以用其他交换操作代替
看看Jon Skeet的答案 - 二进制操作就好^
不好,他们经常会产生碰撞哈希!
public override int GetHashCode() { unchecked { return (str1 ?? String.Empty).GetHashCode() + (str2 ?? String.Empty).GetHashCode(); } }
使用'+'运算符可能比使用'^'更好,因为虽然你明确地想要('AA','BB')和('BB','AA')显然是相同的,你可能不想要( 'AA','AA')和('BB','BB')是相同的(或者所有相等的对).
在这个解决方案中并没有完全遵守'尽快'规则,因为在空值的情况下,这对空字符串执行'GetHashCode()'而不是立即返回已知常量,但即使没有明确测量我也愿意除非你期望很多空值,否则可能会产生一种猜测,即差异不会太大而无法担心.
作为一般规则,为类生成哈希码的一种简单方法是对可以参与生成哈希码的所有数据字段进行异或(小心检查其他人指出的null).这也满足了UserInfo("AA","BB")和UserInfo("BB","AA")的哈希码相同的(人为的)要求.
如果您可以对类的使用做出假设,则可以改进哈希函数.例如,如果str1和str2通常相同,则XOR可能不是一个好的选择.但是,如果str1和str2代表名字和姓氏,那么XOR可能是一个不错的选择.
虽然这显然不是一个真实的例子,但值得指出: - 这可能是使用结构的一个不好的例子:结构通常应该具有值语义,这似乎不是这里的情况. - 使用带有setter的属性来生成哈希码也是一个问题.