HashSet包含方法,意外行为

时间:2014-03-21 15:33:17

标签: c# hashset

我有一个类型Relation,它会覆盖GetHashCodeEquals

    /// <see cref="System.Object.Equals"/>
    public override bool Equals(object obj)
    {
        bool equals = false;
        if (obj is Relation)
        {
            Relation relation = (Relation)obj;
            equals = name.Equals(relation.name);
        }
        return equals;
    }

    /// <see cref="System.Object.GetHashCode"/>
    public override int GetHashCode()
    {
        return name.GetHashCode();
    }

我有两个Relation个对象relation1relation2

我有一个名为HashSet<Relation>的{​​{1}}。

relations

以下代码段应输出HashSet<Relation> relations = new HashSet<Relation>(); relations.Add(relation1); relation1的哈希码。

relation2

输出结果为:

HashSet<Relation>.Enumerator enumerator = relations.GetEnumerator();
enumerator.MoveNext();
Console.WriteLine(relations.Comparer.GetHashCode(enumerator.Current));
Console.WriteLine(relations.Comparer.GetHashCode(relation2));

以下代码段比较134042217 134042217 relation1是否相等。

relation2

输出结果为:

Console.WriteLine(relations.Comparer.Equals(enumerator.Current, relation2));

但是,当我尝试确定hashSet是否包含True 时,我得到了意外的结果。

relation2

输出结果为:

relations.Contains(relation2)

我希望False

以下是我从MSDN中了解到的内容:为了确定元素的存在,True应首先调用Contains然后调用GetHashCode。如果两个方法都返回Equals,那么就会有匹配。

你可以给我一个解释吗?

3 个答案:

答案 0 :(得分:4)

如果在将第一个对象插入HashSet后更改Name,则会发生这种情况。

HashSet记录了对象的原始哈希码,它与第二个对象不同。

答案 1 :(得分:1)

我写了一个测试程序,其中包含你的替代。

internal class Relation
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        bool equals = false;
        if (obj is Relation)
        {
            Relation relation = (Relation)obj;
            equals = Name.Equals(relation.Name);
        }
        return equals;
    }

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

class Program
{
    static void Main(string[] args)
    {
        var relation1 = new Relation() {Name = "Bob"};
        var relation2 = new Relation {Name = "Bob"};
        var relations = new HashSet<Relation>();
        relations.Add(relation1);
        var does = relations.Contains(relation2);
        // does is now true
    }
}

因此,在最小的情况下,您的代码可以满足您的期望。因此,我建议在进行relation1检查时,导致relation2Contains不相同的其他内容会发生。

答案 2 :(得分:0)

根据您的摘要,我写了以下完整示例:

class Program
{
    static void Main(string[] args)
    {
        var r1 = new Relation("name");
        var r2 = new Relation("name");

        HashSet<Relation> r = new HashSet<Relation>();
        r.Add(r1);

        bool test = r.Contains(r2);
    }
}

class Relation
{
    public readonly string Name;

    public Relation(string name)
    {
        Name = name;
    }

    public override bool Equals(object obj)
    {
        bool equals = false;
        if (obj is Relation)
        {
            Relation relation = (Relation)obj;
            equals = Name.Equals(relation.Name);
        }
        return equals;
    }

    /// <see cref="System.Object.GetHashCode"/>
    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

'test'的值为true。我可以解释代码与此示例之间行为差异的唯一方法是,在执行包含检查时,两个对象之间的Name属性不能相同。