我尝试遵循MSDN中的Guidelines并也引用了This great question,但是以下内容似乎不符合预期。

我试图表示一种类似于FQN的结构,其中好像P1在P2之前列出,P2仅与P1存在于同一集合中。像范围是如何工作的。



关于GetHashCode()的主题

我有一类具有这样的属性。

class data{
   public readonly string p1, p2;
   public data(string p1, string p2) {
       this.p1 = p1;
       this.p2 = p2;
   }
   public override int GetHashCode()
   {
       return this.p1.GetHashCode() ^ this.p2.GetHashCode();
   }
  /*also show the equal for comparison*/
    public override bool Equals(System.Object obj)
    {
        if (obj == null)
            return false;
        data d = obj as data;
        if ((System.Object)d == null)
            return false;
        /*I thought this would be smart*/
        return d.ToString() == this.ToString();
    }
    public override string ToString() {
        return "[" + p1 +"][" + p2+ "]";
    }
}


Dictionary(字典)中,我使用data作为键,因此这将使作用域看起来像d1.p1.p2(或者是d1的p1中的p2,但是您更喜欢想象它)

Dictionary<data,int> dict = new Dictionary<data,int>();


我已经检查了d1.p1和另一个d2.p1不同时的行为,该操作可以正确解决。但是,当d1.p1和d2.p1相同且d1和d2的p2不同时,我观察到以下行为。

data d1 = new data(){ p1="p1", p2="p2"  };
data d2 = new data(){ p1="p1", p2="XX"  };
dict.add(d1, 0);
dict.add(d2, 1);
dict[d1] = 4;


结果是两个元素都是4


GetHashCode()是否被正确覆盖?
等于是否正确覆盖?
如果它们都很好,这种行为如何/为什么发生?




关于字典的主题

在监视窗口(VS2013)中,我让字典的键列表显示给我,而不是像我通常期望的那样每个索引一个键,我的数据对象的每个属性都是一个索引的键。因此,我不确定是否存在问题,或者只是误解了“监视”窗口将对象表示为键的形式。我知道VS将如何显示对象,但是我不确定那是我期望它在字典中的键上显示的方式。


我以为GetHashCode()是Dictionary的主要“比较”操作,这始终正确吗?
关键是对象的字典的真正“索引”是什么?


更新

直接查看每个哈希码后,我注意到它们确实重复了。但是,词典未确定该索引是否存在。以下是我看到的数据示例。

1132917379      string: [ABC][ABC]
-565659420      string: [ABC][123]
-1936108909     string: [123][123]
//second loop with next set of strings
1132917379      string: [xxx][xxx]
-565659420      string: [xxx][yyy]
//...etc

最佳答案

GetHachCode()是否被正确覆盖?
  


当然,对于“正确”的一些定义。可能无法很好地重写它,但这不是一个错误的实现(因为该类的两个实例被认为相等,因此将散列为相同的值)。当然,有了该要求,您总是可以从GetHashCode返回0,这将是“正确的”。当然不是很好。

那就是说您的特定实现并不尽如人意。例如,在您的课堂上,字符串的顺序很重要。即new data( "A", "B" ) != new data( "B", "A" )。但是,由于您的GetHashCode实现是对称的,因此它们总是哈希相等。最好以某种方式打破对称性。例如:

public int GetHashCode()
{
    return p1.GetHashCode() ^ ( 13 * p2.GetHashCode() );
}


现在不太可能两个不相等的实例发生冲突。


  
  平等是否被正确覆盖?
  


好吧,它肯定可以改进。例如,第一个空检查是多余的,因此在第二个比较中强制转换为object。整个事情最好写成:

public bool Equals( object obj )
{
    var other = obj as data;
    if( other == null ) return false;
    return p1 == obj.p1 && p2 == obj.p2;
}


我也删除了对ToString的调用,因为它不会显着简化代码或使其更具可读性。这也是执行比较的一种低效方式,因为您必须在比较发生之前就构造两个新的字符串。直接比较成员可以使您有更多的机会尽早使用,更重要的是,它更容易阅读(实际的相等性实现并不取决于字符串表示形式)。


  
  如果它们都很好,这种行为如何/为什么发生?
  


我不知道,因为您提供的代码不会执行此操作。它也不会编译。您的data类具有两个readonly字段,您不能使用初始化程序列表来分配这些字段,如上一个代码片段中所示。

我只能推测您所看到的行为,因为您在此处显示的任何内容都不会导致上述行为。

我能提供的最佳建议是确保您的密钥类不可变。可变类型在Dictionary下不能很好地发挥作用。 Dictionary类不希望对象的哈希码发生变化,因此,如果GetHashCode依赖于类中可变的任何部分,则很可能使事情变得混乱。


  
  我以为GetHachCode()是Dictionary的主要“比较”操作,这始终正确吗?
  


Dictionary仅使用GetHashCode作为“寻址”对象的方式(具体来说,哈希码用于标识应将项目放置在哪个存储桶中)。它不一定直接将其用作比较。如果是的话,它只能使用它来确定两个对象不相等,也不能使用它来确定它们是否相等。


  
  关键是对象的字典的真正“索引”是什么?
  


我不确定您在这里要问什么,但是我倾向于说答案是没有关系。物品去向不重要。如果您关心这种事情,则可能不应该使用Dictionary

关于c# - 了解行为并覆盖GetHashCode(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25193019/

10-13 04:58