Hashtable 的通用版本是什么?

问题描述 投票:0回答:5

我一直在学习 .NET 中泛型的基础知识。但是,我没有看到

Hashtable
的通用等效项。请分享一些用于创建通用哈希表类的示例 C# 代码。

c# .net generics
5个回答
106
投票

Dictionary<TKey, TValue>

请注意,Dictionary 并不是 HashTable 的 100% 替代品。

它们处理 NULL 的方式略有不同。 如果您尝试引用不存在的键,字典将引发异常。 HashTable 将仅返回 null。 原因是该值可能是值类型,而“不能”为 null。在哈希表中,值始终是对象,因此返回 null 至少是可能的。 关于 NULL 的处理,您可以使用 Dictionary

.TryGetValue() 方法,该方法更详细,但允许您安全地检索值,考虑到不存在的键。


43
投票
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); }



22
投票
Dictionary<TKey,TValue>

类 (

link
)。以下是一些示例代码,从使用哈希表转换为最直接的字典等效项(为了简洁起见,删除了参数检查) 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; }

这是一个相当直接的翻译。但问题是,这实际上并没有利用泛型的类型安全特性。第二个函数可以编写如下,并且类型更加安全并且不会产生装箱开销

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; }

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

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; }



5
投票

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 与 Dictionary 进行了一些测试,发现当与字符串键和字符串值对一起使用时,两者的性能大致相同,只是 Hashtable 似乎使用更少的内存。我的测试结果如下:

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



3
投票

System.Collection.Hashtable

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

© www.soinside.com 2019 - 2024. All rights reserved.