HashTable构造函数源码如下:
View Code
public Hashtable(int capacity, float loadFactor) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if ((loadFactor < 0.1f) || (loadFactor > 1f)) { throw new ArgumentOutOfRangeException("loadFactor", Environment.GetResourceString("ArgumentOutOfRange_HashtableLoadFactor", new object[] { 0.1, 1.0 })); } this.loadFactor = 0.72f * loadFactor; double num = ((float) capacity) / this.loadFactor; if (num > 2147483647.0) { throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow")); } int num2 = (num > 3.0) ? HashHelpers.GetPrime((int) num) : 3; this.buckets = new bucket[num2]; this.loadsize = (int) (this.loadFactor * num2); this.isWriterInProgress = false; }
HashTable实质为一个一维数组,即上述源码中的buckets,其初始大小num2由初始指定容量capacity和装载因子loadFactor决定,其实际装载容量loadsize为装在因子*0.72f*初始大小num2。
注:
- capacity: System.Collections.Hashtable 对象最初可包含的元素的近似数目。
- loadFactor: 0.1 到 1.0 范围内的数字,再乘以提供最佳性能的默认值。结果是元素与存储桶的最大比率。
Insert方法源码如下:
View Code
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] private void Insert(object key, object nvalue, bool add) { uint num; uint num2; if (key == null) { throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key")); } if (this.count >= this.loadsize) { this.expand(); } else if ((this.occupancy > this.loadsize) && (this.count > 100)) { this.rehash(); } uint num3 = this.InitHash(key, this.buckets.Length, out num, out num2); int num4 = 0; int index = -1; int num6 = (int) (num % this.buckets.Length); Label_0071: if (((index == -1) && (this.buckets[num6].key == this.buckets)) && (this.buckets[num6].hash_coll < 0)) { index = num6; } if ((this.buckets[num6].key == null) || ((this.buckets[num6].key == this.buckets) && ((this.buckets[num6].hash_coll & 0x80000000L) == 0L))) { if (index != -1) { num6 = index; } Thread.BeginCriticalRegion(); this.isWriterInProgress = true; this.buckets[num6].val = nvalue; this.buckets[num6].key = key; this.buckets[num6].hash_coll |= (int) num3; this.count++; this.UpdateVersion(); this.isWriterInProgress = false; Thread.EndCriticalRegion(); } else if (((this.buckets[num6].hash_coll & 0x7fffffff) == num3) && this.KeyEquals(this.buckets[num6].key, key)) { if (add) { throw new ArgumentException(Environment.GetResourceString("Argument_AddingDuplicate__", new object[] { this.buckets[num6].key, key })); } Thread.BeginCriticalRegion(); this.isWriterInProgress = true; this.buckets[num6].val = nvalue; this.UpdateVersion(); this.isWriterInProgress = false; Thread.EndCriticalRegion(); } else { if ((index == -1) && (this.buckets[num6].hash_coll >= 0)) { this.buckets[num6].hash_coll |= -2147483648; this.occupancy++; } num6 = (int) ((num6 + num2) % ((ulong) this.buckets.Length)); if (++num4 < this.buckets.Length) { goto Label_0071; } if (index == -1) { throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HashInsertFailed")); } Thread.BeginCriticalRegion(); this.isWriterInProgress = true; this.buckets[index].val = nvalue; this.buckets[index].key = key; this.buckets[index].hash_coll |= (int) num3; this.count++; this.UpdateVersion(); this.isWriterInProgress = false; Thread.EndCriticalRegion(); } }
当HashTable也即buckets数组中实际添加元素数超过loadsize时,会调用expand方法使得buckets扩容一倍。
根据要插入的key和buckets的length生成初次要插入的位置num6和发生哈希冲突后要增加的步进量num2,该计算由InitHash函数实现,源码如下:
View Code
private uint InitHash(object key, int hashsize, out uint seed, out uint incr) { uint num = (uint) (this.GetHash(key) & 0x7fffffff); seed = num; incr = 1 + ((uint) (((seed >> 5) + 1) % (hashsize - 1))); return num; }
参见:http://www.cnblogs.com/xiaosuo/archive/2010/03/18/1632341.html