当两个字符串都可以互换时,如何为具有两个字符串的结构实现GetHashCode

Gra*_*ton 67 c# hashtable

我在C#中有一个结构:

public struct UserInfo
{
   public string str1
   {
     get;
     set;
   }

   public string str2
   {
     get;
     set;
   }   
}
Run Code Online (Sandbox Code Playgroud)

唯一的规则是 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))

如何覆盖此结构的GetHashCode函数?

aku*_*aku 66

MSDN:

哈希函数必须具有以下属性:

  • 如果两个对象比较相等,则GetHashCode每个对象的方法必须返回相同的值.但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值.
  • GetHashCode用于一个对象的方法,必须一致,只要没有修改,用于确定对象的的返回值的对象的状态返回相同的散列码Equals方法.请注意,这仅适用于当前应用程序的执行,并且如果再次运行应用程序,则可以返回不同的哈希代码.
  • 为获得最佳性能,哈希函数必须为所有输入生成随机分布.

考虑到正确的方法是:

return str1.GetHashCode() ^ str2.GetHashCode() 
Run Code Online (Sandbox Code Playgroud)

^ 可以用其他交换操作代替

  • 对于任何.net开发者来说,Omer van Kloeten应该是显而易见的.快速样本旨在显示一般的想法,而不是完整的解决方案 (14认同)
  • 此外,不考虑空值. (2认同)
  • 如果你希望你的散列中的str1,str2和str2,str1频繁出现,那么查找速度可能比它应该慢一点.通过缓存哈希码也可以提高查找速度.显然,这些可能是过早的优化. (2认同)

Tom*_*fka 26

看看Jon Skeet的答案 - 二进制操作就好^不好,他们经常会产生碰撞哈希!

  • 但是jon说这很糟糕,因为它会完全符合OP的要求.`F(a,b)== F(b,a)`... (6认同)

小智 15

public override int GetHashCode()
{
    unchecked
    {
        return (str1 ?? String.Empty).GetHashCode() +
            (str2 ?? String.Empty).GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用'+'运算符可能比使用'^'更好,因为虽然你明确地想要('AA','BB')和('BB','AA')显然是相同的,你可能不想要( 'AA','AA')和('BB','BB')是相同的(或者所有相等的对).

在这个解决方案中并没有完全遵守'尽快'规则,因为在空值的情况下,这对空字符串执行'GetHashCode()'而不是立即返回已知常量,但即使没有明确测量我也愿意除非你期望很多空值,否则可能会产生一种猜测,即差异不会太大而无法担心.


Joe*_*Joe 5

  1. 作为一般规则,为类生成哈希码的一种简单方法是对可以参与生成哈希码的所有数据字段进行异或(小心检查其他人指出的null).这也满足了UserInfo("AA","BB")和UserInfo("BB","AA")的哈希码相同的(人为的)要求.

  2. 如果您可以对类的使用做出假设,则可以改进哈希函数.例如,如果str1和str2通常相同,则XOR可能不是一个好的选择.但是,如果str1和str2代表名字和姓氏,那么XOR可能是一个不错的选择.

虽然这显然不是一个真实的例子,但值得指出: - 这可能是使用结构的一个不好的例子:结构通常应该具有值语义,这似乎不是这里的情况. - 使用带有setter的属性来生成哈希码也是一个问题.