为什么当我实现IEqualityComparer时,它有一个GetHashCode(T obj(的参数?当然,它不是一个静态对象,所以为什么我不能只使用当前实例的状态来生成哈希代码呢?是this == obj
吗?
我很好奇,因为我正试图做到这一点:
public abstract class BaseClass : IEqualityComparer<BaseClass>
{
public abstract int GetHashCode(BaseClass obj);
}
public class DerivedClass : BaseClass
{
public int MyData;
public override int GetHashCode(BaseClass obj)
{
return MyData.GetHashCode();
// Or do I have to do this:
// return (DerivedClass)obj.MyData.GetHashCode();
}
}
我试图阻止进行强制转换,因为它被用于真正高性能的代码中。
我认为这里的主要问题是您混淆了IEqualityComparer<T>
和IEquatable<T>
。
IEquatable<T>
定义了一种方法,用于确定当前实例(this
(是否等于相同类型的实例。换句话说,它用于测试objA.Equals(objB)
。在实现此接口时,建议您也重写GetHashCode()
实例方法。
IEqualityComparer<T>
定义了测试给定类型的两个对象是否相等的方法,换句话说,它用于测试comparer.Equals(objA, objB)
。因此,有必要将对象作为参数提供给GetHashCode
(记住,它与从object
继承的GetHashCode
不同(
你可以把IEquatable<T>
想象成你的对象说">这就是我如何知道我是否等于其他东西,"的方式,把IEqualityComparer<T>
想象成你对象说"这是我如何知道其他两个东西是否相等的方式"。
有关如何在框架中使用这两个接口的一些好例子,请参阅:
- 实现
IEquatable<string>
的String
- 实现
IEqualityComparer<string>
的StringComparer
是否应该使用IEqualityComparer<T>
的当前状态来确定哈希代码?如果状态是可变的,那么no在使用散列的任何地方(例如HashSet<T>
或Dictionary<T, V>
(,散列代码都将被缓存并用于高效查找。如果由于比较器的状态发生变化,散列代码可能会发生变化,那么这将完全破坏存储散列的数据结构的有用性。现在,如果状态是不可变的(即,它只在创建比较器时设置,并且在比较器的整个生命周期内不能修改(,那么是的,你可以,但我仍然建议你不要这样做,除非你有充分的理由。
最后,您提到了性能。老实说,这听起来像是过早的优化。我建议您在确定这一特定代码行导致问题之前,不要太担心性能。
如果不使用传入obj
参数中的信息,则哈希代码不会因不同的传入对象而异,也不会有用。Comparer不是您要为其获取哈希代码或与之进行比较的对象的实例。
事实上,您可以在GetHashCode
中使用comaprer的本地字段,甚至可以将MyData
作为哈希代码返回,如您的示例所示——它仍然满足GetHashCode
"为同一对象返回相同值的数据"的要求。但在您的示例中,所有的哈希代码都是相同的,例如comparer,因此将其用于Dictionary
将本质上将字典变成列表。
这同样适用于Equals
调用——事实上,您可以一直返回true
,但它有多有用?