在实现IEqualityComparer时<T>。GetHashCode(T obj),我可以使用当前实例的状态,还是必须使用 obj?



为什么当我实现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,但它有多有用?

最新更新