Какова общая версия Hashtable?

Я изучаю основы генериков в .NET. Однако я не вижу общий эквивалент Hashtable . Пожалуйста, поделитесь некоторым примером кода C # для создания общих classов hash-таблицы.

Dictionary

Обратите внимание, что Словарь не является заменой на HashTable на 100%.

Существует небольшая разница в том, как они обрабатывают NULL. Словарь будет генерировать исключение, если вы попытаетесь ссылаться на ключ, который не существует. HashTable просто вернет null. Причина в том, что значением может быть тип значения, который не может быть нулевым. В Hashtable значение всегда было Object, поэтому возврат null был, по крайней мере, возможен.

Общая версия classа Hashtable – это class System.Collections.Generic.Dictionary .

Пример кода :

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

Общая версия Hashtable – это Dictionary class ( ссылка ). Вот пример кода, переведенного с использованием Hashtable в самый прямой эквивалент словаря (проверка аргументов удалена для краткости)

 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 Create(int[] keys, string[] values) { Dictionary map = Dictionary(); for ( int i = 0; i < keys.Length; i++) { map[keys[i]] = values[i]; } return map; } 

Это довольно прямой перевод. Но проблема в том, что на самом деле это не использует преимущества безопасных типов дженериков. Вторая функция может быть записана следующим образом и быть гораздо более безопасным по типу и не иметь накладных расходов на бокс

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

Даже лучше. Вот полностью общая версия

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

И тот, который еще более гибкий (спасибо Джоулю за то, что я пропустил это)

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

Для тех, кто заинтересован, я создал общий class обертки Hashtable, который полезен для обеспечения безопасности типов и может быть передан как общий тип IDictionary, ICollection и IEnumerable, тогда как не общий Hashtable не может. Ниже приведена реализация.

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

Общая версия System.Collection.HashtableSystem.Collections.Generic.Dictionary .