gpt4 book ai didi

c# - 了解行为并重写 GetHashCode()

转载 作者:行者123 更新时间:2023-11-30 17:47:03 26 4
gpt4 key购买 nike

我试着关注 Guidelines来自 MSDN,也引用了 This great question但下面的行为似乎并不像预期的那样。

我试图表示类似于 FQN 的结构,其中就好像 P1P2 之前列出一样,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 (dict) 中,我使用 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

  1. 是否正确覆盖了 GetHashCode()?
  2. 是否正确覆盖了 Equals?
  3. 如果他们都很好,这种行为是如何发生的/为什么会发生?

关于词典的主题

在监 window 口 (VS2013) 中,我有字典的键列表显示给我,而不是像我通常期望的那样每个索引一个键,我的数据对象的每个属性都是一个索引的键。所以我不确定问题出在哪里,或者我只是误解了 Watch 窗口将对象表示为键。我知道 VS 将如何显示一个对象,但我不确定这就是我希望它在字典中显示一个键的方式。

  1. 我认为 GetHashCode() 是字典的主要“比较”操作,这总是正确的吗?
  2. 对于以对象为键的字典来说,真正的“索引”是什么?

更新

直接查看每个哈希码后,我注意到它们确实重复。然而字典并不确定索引是否存在。下面是我看到的数据示例。

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

最佳答案

  1. Is GetHachCode() overridden correctly?

当然,对于“正确”的某些定义。它可能不会被覆盖很好,但它不是一个不正确的实现(因为被认为相等的类的两个实例将散列为相同的值)。当然,根据该要求,您始终可以从 GetHashCode 返回 0,这将是“正确的”。这肯定不会好。

那是说您的特定实现没有达到应有的水平。例如,在您的类(class)中,字符串的顺序很重要。 IE。 新数据(“A”,“B”)!=新数据(“B”,“A”)。但是,这些将始终哈希相等,因为您的 GetHashCode 实现是对称的。最好以某种方式打破对称性。例如:

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

现在两个不相等的实例发生碰撞的可能性较小。

  1. Is Equal overridden correctly?

嗯,绝对可以改进。例如,第一个 null 检查是多余的,第二次比较中转换为 object 也是多余的。整件事最好写成:

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

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

  1. If they are both fine how/why does this behavior happen?

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

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

我能给出的最佳建议是确保您的键类不可变。 可变类型不能很好地与 Dictionary 搭配使用。 Dictionary 类不希望对象的哈希码发生变化,因此如果 GetHashCode 依赖于类中任何可变的部分,事情很可能会变得非常搞砸了。

  1. I thought GetHachCode() was a Dictionary's primary "comparison" operation, is this always correct?

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

  1. What's the real "Index" to a Dictionary where the key is an object?

我不完全确定您在这里问什么,但我倾向于说答案是无关紧要。元素去哪里并不重要。如果您关心这类事情,您可能不应该使用 Dictionary

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

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com