2009-08-12 44 views
0

所以我想使用引用类型作为关键,.NET字典...什么是.NET Dictionary <T,T>用来散列引用?

例子:

class MyObj 
{ 
    private int mID; 
    public MyObj(int id) 
    { 
     this.mID = id; 
    } 
} 

// whatever code here 
static void Main(string[] args) 
{ 
    Dictionary<MyObj, string> dictionary = new Dictionary<MyObj, string>(); 
} 

我的问题是,对于自定义对象是如何产生的散列(即不是整数,字符串,布尔等)?我问,因为我用作键的对象可能会改变,然后我需要再次查找字典中的东西。如果哈希是从对象的地址生成的,那么我可能没问题......但是如果它是由某个对象的成员变量组合生成的,那么我就麻烦了。

编辑:

我本来应该已经明确表示,我不关心的对象在这种情况下,平等......我只是在寻找一个快速查找(我想做一个1-1协会而不改变相关类的代码)。

由于

+0

我知道我写了这个之后,标题可以是一个有点误导,对此深感抱歉。 – Polaris878 2009-08-12 14:36:38

回答

4

使用的散列是在对象上的.GetHashcode方法的返回值。默认情况下,这基本上是一个代表引用的值。并不保证它是唯一的对象,事实上在很多情况下可能不会。但是特定参考的值在对象的生命周期中不会改变,即使您改变了它。因此,对于此特定的示例,您将会确定。

一般来说,使用不可变的对象作为字典的关键字是非常糟糕的主意。这很容易陷入陷阱中,在该对象上覆盖对象上的Equals和GetHashcode,并中断类型以前用作Dictionary中的键的代码。

+0

是的,但它实际上是散列? – Polaris878 2009-08-12 14:22:10

+0

答案的称号,但没有真正的问题:) – cwap 2009-08-12 14:22:20

+0

@ Polaris878,我扩大了的答案,包括更多的价值 – JaredPar 2009-08-12 14:24:05

2

词典将使用System.Object定义的GetHashCode方法,它不会在对象的生命周期,无论磁场变化等,所以你不会遇到在您所描述的场景中的问题而改变。

您可以覆盖GetHashCode,而且应该这样做,如果你重写Equals使它们相等的对象也返回相同的散列码。但是,如果类型是可变的,那么你必须意识到,如果你使用该对象作为字典的关键字,如果它随后被修改,你将无法再次找到它。

1

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

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

+1

从那时起,MSDN已经更新 - 现在它不是很可怕。仍然过分夸张,但不是可怕的。 – 2009-08-12 14:26:38

+0

谢谢Skeet先生。我已更新我的答案以使用正确的版本。我很惊讶这是第一个出现在谷歌与“默认对象gethashcode”。 – 2009-08-12 14:32:01

+0

那么这两个网页“那里”,以及旧的可能已被引用的比新... – 2009-08-12 14:39:41

7

的GetHashCode的默认实现/基本的Equals处理与身份。您将始终从相同的对象获得相同的散列,并且可能与其他对象不同(很有可能!)。

换句话说,如果你只是想引用的身份,你的罚款。如果您想使用字典处理的按键为(即使用的数据对象中,而不仅仅是对象引用自身,以确定平等的观念),那么这是一个坏主意变异任何equality-的将密钥添加到字典后,将密钥中的敏感数据加密。

object.GetHashCode MSDN文档是有点过于吓人 - 基本上,你不应该使用它持续哈希值(即保存过程调用之间),但它会为同一个对象一致这是所有的要求它成为字典的有效散列。虽然不能保证是独一无二的,但我不认为你会遇到足够的收藏引起问题。

1
  1. 对于CustomObject,从对象得到,散列代码将在物体的开始时产生的,他们将在其整个它的实例的寿命期间保持相同。此外,哈希码永远不会改变,因为内部字段/属性的值将会改变。

  2. 哈希表/字典将不使用的GetHashCode作为唯一的标识符,而是它只会把它当作“散列桶”。例如,字符串“aaa123”和“aaa456”可以具有作为“aaa”的散列,并且具有相同散列“aaa”的所有对象将被存储在一个存储桶中。无论何时您将插入/回顾对象,Dictionary总是会调用GetHashCode并确定存储区以进一步对对象进行个别地址比较。

  3. 自定义对象作为字典键应该被视为如果字典只存储他们的“引用(地址或内存指针)”它不知道它的内容,并且对象的内容改变但引用永远不会改变。这也意味着,如果两个对象是彼此完全相同的副本,但是它们在内存中不同,那么您的散列表不会将它们视为相同,因为它们的内存指针是不同的。以机制保障身份平等

  4. 最好的办法是重写方法“等于”如下......如果您有任何问题。

    class MyObj 
    { 
        private int mID; 
        public MyObj(int id) 
        { 
         this.mID = id; 
        } 
        public bool override Equals(Object obj) 
        { 
         MyObj mobj = obj as MyObj; 
         if(mobj==null) 
          return false; 
         return this.mID == mobj.mID; 
        } 
    } 
    
+0

你有“if(mobj == null)return mobj;”在你的Equals()方法中必须返回一个bool! – mmmmmmmm 2009-08-12 18:39:49

+0

谢谢,修复了.. – 2009-08-12 19:37:45

相关问题