首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >哈希表的通用版本是什么?

哈希表的通用版本是什么?
EN

Stack Overflow用户
提问于 2009-04-21 14:23:56
回答 4查看 54.5K关注 0票数 77

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

EN

回答 4

Stack Overflow用户

发布于 2009-04-21 14:25:38

Hashtable类的泛型版本是System.Collections.Generic.Dictionary类。

Sample code

代码语言:javascript
复制
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);
   }
票数 42
EN

Stack Overflow用户

发布于 2009-04-21 14:31:14

哈希表的泛型版本是Dictionary<TKey,TValue>类(link)。下面是一些示例代码,从使用Hashtable转换为最直接的Dictionary等价物(为了简洁,删除了参数检查)

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
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指出我错过了这一点)

代码语言:javascript
复制
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;
}
票数 22
EN

Stack Overflow用户

发布于 2015-09-12 08:05:13

对于感兴趣的人,我创建了一个泛型Hashtable包装类,它对于强制类型安全很有用,可以作为泛型IDictionary、ICollection和IEnumerable类型传递,而非泛型Hashtable则不能。下面是实现。

代码语言:javascript
复制
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似乎使用了更少的内存。我的测试结果如下:

代码语言:javascript
复制
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
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/772831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档