我尝试遵循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/