重写的等于方法未被哈希集调用



我有一个名为"x"的类,它覆盖了 Equals(),如下所示:

    public override bool Equals(object obj)
    {
        if(obj is x)
        {
            return ((obj as x).key == this.key);
        }
        return false;
    }

当以下扩展方法尝试使用上述覆盖进行比较时,不会使用 Equals():

    public static bool Contains(this HashSet<x> set, char key)
    {
        x SearchKey = new x(key);
        return set.Contains(SearchKey);
    }

仅当我修改 extensio 方法中的第一行时,我才会获得预期的行为,如下所示:

x SearchKey = new x(key);

你能解释一下这种行为吗?

我原以为 Equals() 会对 x 本身的实例进行调用,因为它是 Object 的一个子集。我错过了什么?

首先,正如其他人指出的那样,您还必须覆盖GetHashCode。像这样:

public override int GetHashCode()
{
    return key.GetHashCode();
}

也必须实现IEquatable<T>。集合转到 IEquatable 接口进行比较,该接口是类型安全的,在比较值类型时不会导致装箱/取消装箱。

如前所述,您也应该覆盖GetHashCode。如果您使用的是像 resharper 这样的产品,该工具可以为您自动生成此内容。常见的模式如下所示:

    public virtual bool Equals(Entity other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.Id.Equals(Id);
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (!(obj is Entity)) return false;
        return Equals((Entity)obj);
    }
    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }

在这里,您使用接口方法执行所有基于类型的内容,并使用被覆盖的 Equals(对象) 仅检查类型不变条件,然后强制转换并重定向到接口方法。

有关生成哈希代码的一般最佳实践,请参阅此处的 John Skeets 答案。

您可能需要覆盖 GetHashCode ;)在哈希集中,比较方法是哈希码。