使用基于 GetHashCode 的 Equals 有什么负面影响吗?
Is there any negative consequence in having Equals based on GetHashCode?
下面的代码可以吗?
public override bool Equals(object obj)
{
if (obj == null || !(obj is LicenseType))
return false;
return GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return
Vendor.GetHashCode() ^
Version.GetHashCode() ^
Modifiers.GetHashCode() ^
Locale.GetHashCode();
}
所有属性都是 enums/numeric 字段,并且是定义 LicenseType
对象的唯一属性。
当两个不同的对象返回相同的 HashCode 时会发生什么?
毕竟,它只是一个散列,因此在对象可能具有的所有值范围内可能并不明显。
只有当 GetHashCode
对于每个可能的值都是唯一的时才可以(没有负面影响)。举个例子,short
(一个 16 位值)的 GetHashCode
总是唯一的(希望如此 :-)),所以将 Equals
设为 GetHashCode
没问题。
再比如,对于int
,GetHashCode()
是整数的值,所以我们有((int)value).GetHashCode() == ((int)value)
。请注意,例如 short
并非如此(但 short
的哈希码仍然是唯一的,只是它们使用了更复杂的公式)
请注意,Patrick 写的是错误的,因为 object/class 的“用户”确实如此。你是object/class的“作者”,所以你定义了相等的概念和哈希码的概念。如果你定义两个对象总是相等的,不管它们的值是多少,那就没问题。
public override int GetHashCode() { return 1; }
public override bool Equals(object obj) { return true; }
Equals 唯一重要的 rules 是:
Implementations are required to ensure that if the Equals method returns true for two objects x and y, then the value returned by the GetHashCode method for x must equal the value returned for y.
The Equals method is reflexive, symmetric, and transitive...
很明显你的 Equals()
和 GetHashCode()
可以接受这个规则,所以他们没问题。
出于好奇,至少有一个相等运算符(==
)的例外(通常你根据Equals
方法定义相等运算符)
bool v1 = double.NaN.Equals(double.NaN); // true
bool v2 = double.NaN == double.NaN; // false
这是因为 NaN
值在 IEEE 754 标准中定义为不同于所有值,NaN
包括在内。出于实际原因, Equals
returns true
.
没有,the documentation说的很清楚:
You should not assume that equal hash codes imply object equality.
另外:
Two objects that are equal return hash codes that are equal. However, the reverse is not true: equal hash codes do not imply object equality
并且:
Caution:
- Do not test for equality of hash codes to determine whether two objects are equal. (Unequal objects can have identical hash codes.) To test for equality, call the ReferenceEquals or Equals method.
必须注意,如果两个对象具有相同的哈希码,那么它们就必须相等,这并不是一条规则。
可能的哈希码只有四十亿左右,但显然有超过四十亿个可能的对象。光是十字串就有四十亿多。因此,根据鸽巢原则,必须至少有两个不相等的对象共享相同的哈希码。
假设您有一个 Customer 对象,其中包含许多字段,例如 Name、Address 等。如果您在两个不同的进程中使用完全相同的数据创建两个这样的对象,则它们不必 return 相同的哈希码。如果你在星期二在一个进程中创建这样一个对象,关闭它,然后在星期三再次 运行 程序,哈希码可能会不同。
这在过去曾咬过人。 System.String.GetHashCode
的文档特别指出,两个相同的字符串在不同版本的 CLR 中可以具有不同的哈希码,事实上它们确实如此。不要将字符串哈希存储在数据库中并期望它们永远相同,因为它们不会。
下面的代码可以吗?
public override bool Equals(object obj)
{
if (obj == null || !(obj is LicenseType))
return false;
return GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return
Vendor.GetHashCode() ^
Version.GetHashCode() ^
Modifiers.GetHashCode() ^
Locale.GetHashCode();
}
所有属性都是 enums/numeric 字段,并且是定义 LicenseType
对象的唯一属性。
当两个不同的对象返回相同的 HashCode 时会发生什么?
毕竟,它只是一个散列,因此在对象可能具有的所有值范围内可能并不明显。
只有当 GetHashCode
对于每个可能的值都是唯一的时才可以(没有负面影响)。举个例子,short
(一个 16 位值)的 GetHashCode
总是唯一的(希望如此 :-)),所以将 Equals
设为 GetHashCode
没问题。
再比如,对于int
,GetHashCode()
是整数的值,所以我们有((int)value).GetHashCode() == ((int)value)
。请注意,例如 short
并非如此(但 short
的哈希码仍然是唯一的,只是它们使用了更复杂的公式)
请注意,Patrick 写的是错误的,因为 object/class 的“用户”确实如此。你是object/class的“作者”,所以你定义了相等的概念和哈希码的概念。如果你定义两个对象总是相等的,不管它们的值是多少,那就没问题。
public override int GetHashCode() { return 1; }
public override bool Equals(object obj) { return true; }
Equals 唯一重要的 rules 是:
Implementations are required to ensure that if the Equals method returns true for two objects x and y, then the value returned by the GetHashCode method for x must equal the value returned for y.
The Equals method is reflexive, symmetric, and transitive...
很明显你的 Equals()
和 GetHashCode()
可以接受这个规则,所以他们没问题。
出于好奇,至少有一个相等运算符(==
)的例外(通常你根据Equals
方法定义相等运算符)
bool v1 = double.NaN.Equals(double.NaN); // true
bool v2 = double.NaN == double.NaN; // false
这是因为 NaN
值在 IEEE 754 标准中定义为不同于所有值,NaN
包括在内。出于实际原因, Equals
returns true
.
没有,the documentation说的很清楚:
You should not assume that equal hash codes imply object equality.
另外:
Two objects that are equal return hash codes that are equal. However, the reverse is not true: equal hash codes do not imply object equality
并且:
Caution:
- Do not test for equality of hash codes to determine whether two objects are equal. (Unequal objects can have identical hash codes.) To test for equality, call the ReferenceEquals or Equals method.
必须注意,如果两个对象具有相同的哈希码,那么它们就必须相等,这并不是一条规则。
可能的哈希码只有四十亿左右,但显然有超过四十亿个可能的对象。光是十字串就有四十亿多。因此,根据鸽巢原则,必须至少有两个不相等的对象共享相同的哈希码。
假设您有一个 Customer 对象,其中包含许多字段,例如 Name、Address 等。如果您在两个不同的进程中使用完全相同的数据创建两个这样的对象,则它们不必 return 相同的哈希码。如果你在星期二在一个进程中创建这样一个对象,关闭它,然后在星期三再次 运行 程序,哈希码可能会不同。
这在过去曾咬过人。 System.String.GetHashCode
的文档特别指出,两个相同的字符串在不同版本的 CLR 中可以具有不同的哈希码,事实上它们确实如此。不要将字符串哈希存储在数据库中并期望它们永远相同,因为它们不会。