我想根据上面的答案和我自己的经验来看看一些具体的场景。
一个经验法则是,具有不同哈希码的两个实例应该始终不相等,但如果它们具有相同的哈希码,它们可能相等也可能不相等。GetHashCode()
用于快速区分实例,并Equals()
用于验证相等性(无论这对您意味着什么)。
此外,许多内置机制都在寻找 的实现,IEquatable<T>
因此最好声明一个Equals(MyClass)
实际执行检查的覆盖。
具有唯一 ID 的类
考虑一个具有唯一 ID 的类。然后 equals 操作将只检查 id。与哈希相同,它仅依赖于 id。
public class IdClass : IEquatable<IdClass>
{
public int ID { get; } // Assume unique
public string Name { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(IdClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is IdClass other)
{
return Equals(other);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="IdClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="IdClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public virtual bool Equals(IdClass other)
{
if (other == null) return false;
return ID.Equals(other.ID);
}
/// <summary>
/// Calculates the hash code for the <see cref="IdClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode() => ID.GetHashCode();
#endregion
}
具有属性的类
这种情况与上面类似,但是比较依赖于两个或多个属性,并且需要在哈希码中进行非对称组合。这将在下一个场景中变得更加明显,但想法是如果一个属性具有 hashA
而另一个属性 hash B
,结果应该不同于第一个属性具有 hashB
和另一个 hash的情况A
。
public class RefClass : IEquatable<RefClass>
{
public string Name { get; }
public int Age { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(RefClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is RefClass other)
{
return Equals(other);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="RefClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="RefClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public virtual bool Equals(RefClass other)
{
if (other == null) { return false; }
return Name.Equals(other.Name)
&& Age.Equals(other.Age);
}
/// <summary>
/// Calculates the hash code for the <see cref="RefClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295) * hc + Name.GetHashCode();
hc = (-1521134295) * hc + Age.GetHashCode();
return hc;
}
}
#endregion
}
基于值的类(结构)
这几乎与上面的情况相同,除了作为值类型(struct
声明)还需要重新定义==
和!=
调用equals。
public struct ValClass : IEquatable<ValClass>
{
public int X { get; }
public int Y { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(ValClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is ValClass other)
{
return Equals(other);
}
return false;
}
public static bool operator ==(ValClass target, ValClass other) { return target.Equals(other); }
public static bool operator !=(ValClass target, ValClass other) { return !(target == other); }
/// <summary>
/// Checks for equality among <see cref="ValClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="ValClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public bool Equals(ValClass other)
{
return X == other.X && Y == other.Y;
}
/// <summary>
/// Calculates the hash code for the <see cref="ValClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295) * hc + X.GetHashCode();
hc = (-1521134295) * hc + Y.GetHashCode();
return hc;
}
}
#endregion
}
注意struct
应该是不可变的,最好readonly
在声明中添加关键字
public readonly struct ValClass : IEquatable<ValClass>
{
}