Hashtable 中的键值修改问题
时间:2010-12-10 来源:haogj
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Collections;
6 using System.Threading;
7
8 namespace HashtableDemo
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 //第一次输出
15 // not
16 Hashtable ha = new Hashtable();
17 for (int i = 0; i < 5; i++)
18 ha.Add(new cuskey(i), i);
19
20 if (ha.ContainsKey(new cuskey(3)))
21 Console.WriteLine("find");
22 else
23 Console.WriteLine("Can't find");
24
25 ha.Clear();
26
27 //第二次输出
28 // ok
29 MyTest t = new MyTest(10);
30 ha.Add(t, 10);
31 if (ha.ContainsKey(new MyTest(10)))
32 {
33 Console.WriteLine("find");
34 }
35 else
36 Console.WriteLine("Can't find");
37
38 //第三次输出
39 // ok
40 Console.WriteLine(ha[new MyTest(10)]);
41
42 //第四次输出
43 //
44 t.KeyNum = 11;
45
46 if (ha.ContainsKey(new MyTest(11)))
47 {
48 Console.WriteLine("find 11");
49 }
50 else if (ha.ContainsKey(new MyTest(10)))
51 Console.WriteLine("find 10");
52 else
53 Console.WriteLine("Can't find");
54
55
56
57 //第五次输出
58 Console.WriteLine(ha.Count);
59
60 //第六次输出
61 MyTest mt = new MyTest(11);
62 ha.Add(mt, 11);
63 Console.WriteLine(ha.Count);
64
65 //第七次输出
66 foreach (DictionaryEntry item in ha)
67 {
68 Console.WriteLine((item.Key as MyTest).KeyNum);
69 Console.WriteLine(item.Value);
70 }
71
72 Console.ReadLine();
73 }
74 }
75
76 class MyTest
77 {
78 int keyNum;
79
80 public int KeyNum
81 {
82 get { return keyNum; }
83 set { keyNum = value; }
84 }
85
86 public MyTest(int num)
87 {
88 keyNum = num;
89 }
90
91 public override int GetHashCode()
92 {
93 return keyNum;
94 }
95
96 public override bool Equals(object obj)
97 {
98 return keyNum == ((MyTest)obj).KeyNum;
99 }
100 }
101
102 class cuskey
103 {
104 int keyNum;
105
106 public int KeyNum
107 {
108 get { return keyNum; }
109 set { keyNum = value; }
110 }
111
112 public cuskey(int num)
113 {
114 keyNum = num;
115 }
116 }
117 }
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Collections;
6 using System.Threading;
7
8 namespace HashtableDemo
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 //第一次输出
15 // not
16 Hashtable ha = new Hashtable();
17 for (int i = 0; i < 5; i++)
18 ha.Add(new cuskey(i), i);
19
20 if (ha.ContainsKey(new cuskey(3)))
21 Console.WriteLine("find");
22 else
23 Console.WriteLine("Can't find");
24
25 ha.Clear();
26
27 //第二次输出
28 // ok
29 MyTest t = new MyTest(10);
30 ha.Add(t, 10);
31 if (ha.ContainsKey(new MyTest(10)))
32 {
33 Console.WriteLine("find");
34 }
35 else
36 Console.WriteLine("Can't find");
37
38 //第三次输出
39 // ok
40 Console.WriteLine(ha[new MyTest(10)]);
41
42 //第四次输出
43 //
44 t.KeyNum = 11;
45
46 if (ha.ContainsKey(new MyTest(11)))
47 {
48 Console.WriteLine("find 11");
49 }
50 else if (ha.ContainsKey(new MyTest(10)))
51 Console.WriteLine("find 10");
52 else
53 Console.WriteLine("Can't find");
54
55
56
57 //第五次输出
58 Console.WriteLine(ha.Count);
59
60 //第六次输出
61 MyTest mt = new MyTest(11);
62 ha.Add(mt, 11);
63 Console.WriteLine(ha.Count);
64
65 //第七次输出
66 foreach (DictionaryEntry item in ha)
67 {
68 Console.WriteLine((item.Key as MyTest).KeyNum);
69 Console.WriteLine(item.Value);
70 }
71
72 Console.ReadLine();
73 }
74 }
75
76 class MyTest
77 {
78 int keyNum;
79
80 public int KeyNum
81 {
82 get { return keyNum; }
83 set { keyNum = value; }
84 }
85
86 public MyTest(int num)
87 {
88 keyNum = num;
89 }
90
91 public override int GetHashCode()
92 {
93 return keyNum;
94 }
95
96 public override bool Equals(object obj)
97 {
98 return keyNum == ((MyTest)obj).KeyNum;
99 }
100 }
101
102 class cuskey
103 {
104 int keyNum;
105
106 public int KeyNum
107 {
108 get { return keyNum; }
109 set { keyNum = value; }
110 }
111
112 public cuskey(int num)
113 {
114 keyNum = num;
115 }
116 }
117 }
然后,发现一个问题:
在第四次我用了两个键去匹配,都是Can't find,但是在第七次输出的时候怎么就能找到确实是KeyNum=11的实例,这是怎么回事???
当我们在 Hashtable 中通过键来保存值的时候,Hashtable 会通过键对象的 HashCode 来确定内容保存在表中的位置,同时还要保存这个键对象的引用。
当我们通过 ContainsKey 来查找的时候,Hashtable 将会取得原来键对象的 HashCode 与现在的查找对象的 HashCode 去比较。如果相同,再通过 HashCode 在内部存储中找到保存的值。
在第四次的时候,使用 11 的时候,可以与原来的键对象相同,但是,原来通过 10 保存,现在使用 HashCode 11 来查找,有问题,所以找不到。
在使用 10 的时候,与原来的键对象都不相同,所以,更加找不到。
但是,在 Hashtable 中确实保存着一个条目。所以,在第七次的时候可以遍历到。
所以,如果通过一个对象作为键在 Hashtable 中保存数据,那么,一旦修改了这个键对象,就没有办法通过键对象来找到原来保存的值。
正确的方式是,先移除原来的键值对,然后修改键对象,最后,保存新的键值对。
在 CLR Via C# 中文 第三版的 130 页中间,Jeffrey 也提到了这个问题。
相关阅读 更多 +