什么是Hashtable的通用版本?

我一直在.NET中学习generics的基础知识。 但是,我没有看到Hashtable的通用等价物。 请分享一些示例C#代码来创buildgenerics哈希表类。

Dictionary<TKey, TValue>

请注意,字典不是100%的替代HashTable的下降。

它们处理NULL的方式稍有不同。 如果您尝试引用不存在的键,字典将会引发exception。 HashTable将只返回null。 原因是值可能是一个值types,它不能为空。 在一个Hashtable中,这个值始终是Object,所以返回null至less是可能的。

Hashtable类的通用版本是System.Collections.Generic.Dictionary类。

示例代码 :

 Dictionary<int, string> numbers = new Dictionary<int, string>( ); numbers.Add(1, "one"); numbers.Add(2, "two"); // Display all key/value pairs in the Dictionary. foreach (KeyValuePair<int, string> kvp in numbers) { Console.WriteLine("Key: " + kvp.Key + "\tValue: " + kvp.Value); } 

Hashtable的通用版本是Dictionary<TKey,TValue>类( 链接 )。 下面是一些使用Hashtable翻译成最直接等效的Dictionary的示例代码(为简洁起见删除了参数检查)

 public HashTable Create(int[] keys, string[] values) { HashTable table = new HashTable(); for ( int i = 0; i < keys.Length; i++ ) { table[keys[i]] = values[i]; } return table; } public Dictionary<object,object> Create(int[] keys, string[] values) { Dictionary<object,object> map = Dictionary<object,object>(); for ( int i = 0; i < keys.Length; i++) { map[keys[i]] = values[i]; } return map; } 

这是一个相当直接的翻译。 但问题是这实际上并没有利用generics的types安全特性。 第二个函数可以写成如下,更安全的types,并没有拳击开销

 public Dictionary<int,string> Create(int[] keys, string[] values) { Dictionary<int,string> map = Dictionary<int,string>(); for ( int i = 0; i < keys.Length; i++) { map[keys[i]] = values[i]; } return map; } 

更好。 这是一个完全通用的版本

 public Dictionary<TKey,TValue> Create<TKey,TValue>(TKey[] keys, TValue[] values) { Dictionary<TKey,TValue> map = Dictionary<TKey,TValue>(); for ( int i = 0; i < keys.Length; i++) { map[keys[i]] = values[i]; } return map; } 

还有一个更加灵活的(感谢Joel指出我错过了这个)

 public Dictionary<TKey,TValue> Create<TKey,TValue>( IEnumerable<TKey> keys, IEnumerable<TValue> values) { Dictionary<TKey,TValue> map = Dictionary<TKey,TValue>(); using ( IEnumerater<TKey> keyEnum = keys.GetEnumerator() ) using ( IEnumerator<TValue> valueEnum = values.GetEnumerator()) { while (keyEnum.MoveNext() && valueEnum.MoveNext() ) { map[keyEnum.Current] = valueEnum.Current; } } return map; } 

对于那些有兴趣的人,我创build了一个通用的Hashtable包装类,这对于强制types安全是有用的,可以作为genericsIDictionary,ICollection和IEnumerabletypes传递,而非genericsHashtable不能。 以下是实施。

 using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace Common.Collections.Generic { public class Hashtable<TKey, TValue> : IDictionary<TKey, TValue> , ICollection<KeyValuePair<TKey, TValue>> , IEnumerable<KeyValuePair<TKey, TValue>> , IDictionary , ICollection , IEnumerable { protected Hashtable _items; /// <summary> /// Initializes a new, empty instance of the Hashtable class using the default initial capacity, load factor, hash code provider, and comparer. /// </summary> public Hashtable() { _items = new Hashtable(); } /// <summary> /// Initializes a new, empty instance of the Hashtable class using the specified initial capacity, and the default load factor, hash code provider, and comparer. /// </summary> /// <param name="capacity">The approximate number of elements that the Hashtable object can initially contain. </param> public Hashtable(int capacity) { _items = new Hashtable(capacity); } /// <summary> /// Actual underlying hashtable object that contains the elements. /// </summary> public Hashtable Items { get { return _items; } } /// <summary> /// Adds an element with the specified key and value into the Hashtable. /// </summary> /// <param name="key">Key of the new element to add.</param> /// <param name="value">Value of the new elment to add.</param> public void Add(TKey key, TValue value) { _items.Add(key, value); } /// <summary> /// Adds an element with the specified key and value into the Hashtable. /// </summary> /// <param name="item">Item containing the key and value to add.</param> public void Add(KeyValuePair<TKey, TValue> item) { _items.Add(item.Key, item.Value); } void IDictionary.Add(object key, object value) { this.Add((TKey)key, (TValue)value); } /// <summary> /// Add a list of key/value pairs to the hashtable. /// </summary> /// <param name="collection">List of key/value pairs to add to hashtable.</param> public void AddRange(IEnumerable<KeyValuePair<TKey, TValue>> collection) { foreach (var item in collection) _items.Add(item.Key, item.Value); } /// <summary> /// Determines whether the Hashtable contains a specific key. /// </summary> /// <param name="key">Key to locate.</param> /// <returns>True if key is found, otherwise false.</returns> public bool ContainsKey(TKey key) { return _items.ContainsKey(key); } /// <summary> /// Determines whether the Hashtable contains a specific key. /// </summary> /// <param name="item">Item containing the key to locate.</param> /// <returns>True if item.Key is found, otherwise false.</returns> public bool Contains(KeyValuePair<TKey, TValue> item) { return _items.ContainsKey(item.Key); } bool IDictionary.Contains(object key) { return this.ContainsKey((TKey)key); } /// <summary> /// Gets an ICollection containing the keys in the Hashtable. /// </summary> public ICollection<TKey> Keys { get { return _items.ToList<TKey>(); } } ICollection IDictionary.Keys { get { return this.Keys.ToList(); } } /// <summary> /// Gets the value associated with the specified key. /// </summary> /// <param name="key">The key of the value to get.</param> /// <param name="value">When this method returns, contains the value associated with the specified key, /// if the key is found; otherwise, the default value for the type of the value parameter. This parameter /// is passed uninitialized.</param> /// <returns>true if the hashtable contains an element with the specified key, otherwise false.</returns> public bool TryGetValue(TKey key, out TValue value) { value = (TValue)_items[key]; return (value != null); } /// <summary> /// Gets an ICollection containing the values in the Hashtable. /// </summary> public ICollection<TValue> Values { get { return _items.Values.ToList<TValue>(); } } ICollection IDictionary.Values { get { return this.Values.ToList(); } } /// <summary> /// Gets or sets the value associated with the specified key. /// </summary> /// <param name="key">The key whose value to get or set. </param> /// <returns>The value associated with the specified key. If the specified key is not found, /// attempting to get it returns null, and attempting to set it creates a new element using the specified key.</returns> public TValue this[TKey key] { get { return (TValue)_items[key]; } set { _items[key] = value; } } /// <summary> /// Removes all elements from the Hashtable. /// </summary> public void Clear() { _items.Clear(); } /// <summary> /// Copies all key/value pairs in the hashtable to the specified array. /// </summary> /// <param name="array">Object array to store objects of type "KeyValuePair&lt;TKey, TValue&gt;"</param> /// <param name="arrayIndex">Starting index to store objects into array.</param> public void CopyTo(Array array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } /// <summary> /// Copies all key/value pairs in the hashtable to the specified array. /// </summary> /// <param name="array">Object array to store objects of type "KeyValuePair&lt;TKey, TValue&gt;"</param> /// <param name="arrayIndex">Starting index to store objects into array.</param> public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } /// <summary> /// Gets the number of key/value pairs contained in the Hashtable. /// </summary> public int Count { get { return _items.Count; } } /// <summary> /// Gets a value indicating whether the Hashtable has a fixed size. /// </summary> public bool IsFixedSize { get { return _items.IsFixedSize; } } /// <summary> /// Gets a value indicating whether the Hashtable is read-only. /// </summary> public bool IsReadOnly { get { return _items.IsReadOnly; } } /// <summary> /// Gets a value indicating whether access to the Hashtable is synchronized (thread safe). /// </summary> public bool IsSynchronized { get { return _items.IsSynchronized; } } /// <summary> /// Gets an object that can be used to synchronize access to the Hashtable. /// </summary> public object SyncRoot { get { return _items.SyncRoot; } } /// <summary> /// Removes the element with the specified key from the Hashtable. /// </summary> /// <param name="key">Key of the element to remove.</param> public void Remove(TKey key) { _items.Remove(key); } /// <summary> /// Removes the element with the specified key from the Hashtable. /// </summary> /// <param name="item">Item containing the key of the element to remove.</param> public void Remove(KeyValuePair<TKey, TValue> item) { this.Remove(item.Key); } bool IDictionary<TKey, TValue>.Remove(TKey key) { var numValues = _items.Count; _items.Remove(key); return numValues > _items.Count; } bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { var numValues = _items.Count; _items.Remove(item.Key); return numValues > _items.Count; } void IDictionary.Remove(object key) { _items.Remove(key); } /// <summary> /// Returns an enumerator that iterates through the hashtable. /// </summary> /// <returns>An enumerator for a list of key/value pairs.</returns> public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { foreach (DictionaryEntry? item in _items) yield return new KeyValuePair<TKey, TValue>((TKey)item.Value.Key, (TValue)item.Value.Value); } /// <summary> /// Returns an enumerator that iterates through the hashtable. /// </summary> /// <returns>An enumerator for a list of key/value pairs as generic objects.</returns> IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } IDictionaryEnumerator IDictionary.GetEnumerator() { // Very old enumerator that no one uses anymore, not supported. throw new NotImplementedException(); } object IDictionary.this[object key] { get { return _items[(TKey)key]; } set { _items[(TKey)key] = value; } } } } 

我已经做了一些这个Hashtable与字典的testing,发现这两个执行大约相同时使用string键和string值对,除了Hashtable似乎使用较less的内存。 我的testing结果如下:

 TestInitialize Dictionary_50K_Hashtable Number objects 50000, memory usage 905164 Insert, 22 milliseconds. A search not found, 0 milliseconds. Search found, 0 milliseconds. Remove, 0 milliseconds. Search found or not found, 0 milliseconds. TestCleanup Dictionary_50K_Hashtable TestInitialize Dictionary_50K_Dictionary Number objects 50000, memory usage 1508316 Insert, 16 milliseconds. A search not found, 0 milliseconds. Search found, 0 milliseconds. Remove, 0 milliseconds. Search found or not found, 0 milliseconds. TestCleanup Dictionary_50K_Dictionary 

System.Collection.Hashtable的通用版本是System.Collections.Generic.Dictionary<TKey, TValue>