当两个字符串都可以互换时,如何实现具有两个字符串的结构的GetHashCode
我在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函数?
解决方案
回答
许多可能性。例如。
返回str1.GetHashCode()^ str1.GetHashCode()
回答
也许像str1.GetHashCode()+ str2.GetHashCode()一样?或者(str1.GetHashCode()+ str2.GetHashCode())/ 2?这样,无论str1和str2是否被交换都将是相同的。
回答
试试这个:
(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()
回答
对它们进行排序,然后将它们串联:
return ((str1.CompareTo(str2) < 1) ? str1 + str2 : str2 + str1) .GetHashCode();
回答
GetHashCode的结果应为:
- 尽可能快地。
- 尽可能独特。
牢记这些,我会选择这样的内容:
if (str1 == null) if (str2 == null) return 0; else return str2.GetHashCode(); else if (str2 == null) return str1.GetHashCode(); else return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();
编辑:忘记了空值。代码固定。
回答
MSDN:
哈希函数必须具有以下属性:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values. The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again. For the best performance, a hash function must generate a random distribution for all input.
考虑到正确的方法是:
return str1.GetHashCode() ^ str2.GetHashCode()
可以用其他交换运算来代替
回答
是的,正如Gary Shutler指出的那样:
return str1.GetHashCode() + str2.GetHashCode();
会溢出。我们可以尝试按Artem的建议进行强制转换,也可以将语句放在unchecked关键字中:
return unchecked(str1.GetHashCode() + str2.GetHashCode());
回答
太复杂了,忘记了null等。它用于存储分区之类的东西,因此我们可以摆脱诸如
if (null != str1) { return str1.GetHashCode(); } if (null != str2) { return str2.GetHashCode(); } //Not sure what you would put here, some constant value will do return 0;
通过假设在异常大比例的实例中str1不太可能是常见的,这是有偏见的。
回答
public override int GetHashCode() { unchecked { return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0); } }
回答
public override int GetHashCode() { unchecked { return (str1 ?? String.Empty).GetHashCode() + (str2 ?? String.Empty).GetHashCode(); } }
使用'+'运算符可能比使用'^'更好,因为尽管我们明确希望('AA','BB')和('BB','AA')明确相同,但我们可能不希望( 'AA','AA')和('BB','BB')相同(或者与此完全相同的对)。
在此解决方案中并未完全遵守"尽可能快"的规则,因为在为null的情况下,它将对空字符串执行" GetHashCode()",而不是立即返回已知常量,但是即使我没有明确地测量冒一个猜想,除非我们期望很多null,否则差异将不足以担心。
回答
- 通常,生成类的哈希码的一种简单方法是对可以参与生成哈希码的所有数据字段进行XOR(小心检查其他人指出的null)。这也满足(人工?)要求,即UserInfo(" AA"," BB")和UserInfo(" BB"," AA")的哈希码相同。
- 如果可以对类的使用做出假设,则可以改善哈希函数。例如,如果str1和str2相同是很常见的,那么XOR可能不是一个好选择。但是,如果str1和str2分别代表名字和姓氏,那么XOR可能是一个不错的选择。
尽管这显然不是一个真实的例子,但值得指出的是:
这可能是使用结构的一个较差的示例:结构通常应具有值语义,在这里似乎并非如此。
使用带有setter的属性来生成哈希码也很麻烦。
回答
请参阅乔恩·斯基特(Jon Skeet)的答案,例如^
的二进制运算不好,它们经常会生成冲突哈希!