哈希代码会为具有相同属性的对象提供相同的结果

时间:2012-08-30 09:16:18

标签: c# hashcode

如果我有引用类型对象,我创建了两个具有相同属性的对象 他们会有相同的哈希码吗?

样本类:

class Person
{
   int id;
   string name;

   public Person(int pid, string pname)
   {
      this.id = pid;
      this.name = pname;
   }
}

然后定义两个对象:

Person p1 = new Person(1,"xxx");
Perdon p2 = new Person(1,"xxx");
  

// p1.GetHashCode()= p2.GetHashCode()??

编辑:我尝试了这段代码并获得了不同的结果,但测试字符串上的东西给了我相同的结果
那我为什么要问

4 个答案:

答案 0 :(得分:1)

如果Person是结构,那么将从成员值生成哈希码,您将获得相同的结果。但是,对于类,默认的哈希码实现将根据内存引用为每个对象提供唯一的哈希码。

所以在这种情况下,如果你想要p1和p2的相同哈希码,你必须提供自己的实现。

答案 1 :(得分:1)

您有责任自己实施GetHashCode。如果你不这样做,他们就不会有相同的哈希码。

答案 2 :(得分:1)

在此处查看默认实现: http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

GetHashCode方法的默认实现不保证不同对象的唯一返回值。此外,.NET Framework不保证GetHashCode方法的默认实现,并且它返回的值在不同版本的.NET Framework之间是相同的。因此,不得将此方法的默认实现用作散列目的的唯一对象标识符。

但我认为你真正想知道的是哈希码是如何工作的。

假设你有以下课程:

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }
}

现在,假设你要比较两个人并检查他们是否有相同的名字,你是怎么做到的?您覆盖在Object中实现的equals。 (隐式地在C#中扩展Object的所有类) 像这样:

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }

    public override bool Equals(Object obj)
    {
        if(obj == null)
            return false // not equal if obj is null

        Equals temp = obj as Equals; // temp set to null if obj can not be cast to equals
        if(p == null)
            return false

        // if code gets here, the code object passed is an instance of Equals.
        // Now we have to check if the strings match.
        bool isEqual = p.name == this.name; // set if the two names match
        return isEqual; // return if these two match
    }
}

现在,您可以检查两个人是否平等。 例如:

Person p1 = new Person("Jack");
Person p2 = new Person("Jack");
Person p3 = new Person("Jill");
Object p4 = new Person("Jill");

p1.Equals(p2) // returns true
p1.Equals(p3) // returns false
p4.Equals(p1) // returns false
p4.Equals(p3) // returns true

现在,假设您有一个庞大的人员列表,例如一百万,您想知道此列表中是否存在名为"amy"的人员。你怎么会找到这个人的?你会逐个遍历所有的名字,并检查那个人是否等于amy?但那将是非常缓慢的,如果amy是这个名单中的第一百万人呢?我们如何提高绩效?

输入Hashcodes。

假设您编写了一个简单的哈希码算法: 哈希码是人名中每个字母的每个数字的总和。

public Person
{
    private string name;
    public Person(Name name)
    {
        this.name = name;
    }

    public  override bool Equals(Object obj)
    {
        if(obj == null)
            return false // not equal if obj is null

        Equals temp = obj as Equals; // temp set to null if obj can not be cast to equals
        if(p == null)
            return false

        // if code gets here, the code object passed is an instance of Equals.
        // Now we have to check if the strings match.
        bool isEqual = p.name == this.name; // set if the two names match
        return isEqual; // return if these two match
    }

    public override int GetHashCode()
    {
        int sum = 0;
        foreach(char c in this.name)
        {
            sum += c;
        }
        return sum;
    }
}

因此,如果我们amy她的哈希码为1 + 13 + 25,那么38

现在,您将拥有一个名为“buckets”的列表,而不是普通列表。您的哈希码决定您去哪个桶。 amy 38如果38进入货架may,则会有一个密码。

现在假设我们有另一个人,姓名38,她的名字中有相同的字母,所以她的哈希码也是38,她也进入了38

现在,每当你想检查这个列表中是否存在amy时。我们首先检查她的哈希码,38,现在我们去看看桶38,然后遍历桶38中的所有对象,我们检查桶amy中的任何对象是否与amy匹配如果为true,则返回true,如果为false,则返回false。因此,如果您有一百万人,那么您必须要知道的列表是否存在此列表中{{1}}是否会大幅减少。

所以基本上如果你要使用哈希码,你将不得不遵守以下规则:

  • 你必须覆盖&如果您要使用哈希码,则实现等于。
  • 对于Equals返回true的两个对象,它们必须始终具有相同的哈希码
  • 两个不同的对象可能具有相同的哈希码,但不一定必须相同。

这基本上就是它的主旨。

答案 3 :(得分:0)

默认情况下,他们不会(对于参考类型)。你可以尝试一下,看看。

如果您希望它们具有相同的哈希码,则必须相应地编写自己的GetHashCode()。