2009-04-21 12 views
65

私は.NETでジェネリックスの基礎を学んできました。しかし、私はHashtableの一般的な等価物が表示されません。ジェネリックハッシュテーブルクラスを作成するためのサンプルC#コードをいくつかご紹介してください。Hashtableの一般的なバージョンは何ですか?

答えて

91

Dictionary<TKey, TValue>

辞書ハッシュテーブルの交換で100%の低下ではないことに注意してください。

NULLを処理する方法に若干の違いがあります。 存在しないキーを参照しようとすると、ディクショナリは例外をスローします。 HashTableはnullを返します。 その理由は、値が値型である可能性があります。をnullにできないためです。ハッシュテーブルでは、値は常にObjectであるため、nullを返すことは少なくとも可能でした。

+3

もう1つの違いは、項目が削除されない場合、書き込み中の任意の数のリーダースレッドによって「HashTable」に安全にアクセスできることです(スレッドではないことです複数のライターにとって安全です)。対照的に、 'Dictionary 'は、アドオンのみのシナリオであっても、複数の読者、ゼロのライター以外のシナリオではスレッドセーフではありません。 – supercat

+6

それは良い点です。ただし、.NET 4では[ConcurrentDictionary ](https://msdn.microsoft.com/en-us/library/dd287191%28v=vs.100%29)が導入されています。aspx)は、 'System.Collections.Concurrent'の他のコレクションのようにスレッドセーフです。 – J0e3gan

3
+0

私はいつ他のものを使いますか? – johnny

+0

.NET 1.xとの相互運用性を維持しようとしていない限り、ジェネリックコレクション以外のコレクションを使用する利点はありません。 – bdukes

+0

詳細説明については、MSDNの汎用コレクションの使用時期(http://msdn.microsoft.com/en-us/library/ms172181.aspx)を参照してください。 – bdukes

41

ハッシュテーブルクラスの汎用バージョンは、System.Collections.Generic.Dictionaryクラスです。

Sample code

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); 
    } 
+1

MSDN lobandバージョンへのリンクを編集しました。 –

+2

好奇心。なぜマイクロソフトは辞書をハッシュテーブルと呼び、ハッシュテーブルをハッシュテーブルと呼びますか?私がジェネリックの辞書について読むまで、ハッシュテーブルはいつも私に不思議そうでした。 – johnny

21

のHashtableのジェネリックバージョンは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; 
} 

をinccurすることはできませんでした。ここで、私は一般的なHashtableのラッパークラスを作成し、完全にジェネリックバージョン

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

そして、さらに柔軟である1(おかげでジョエルは、私はこれを逃し指摘のため)です興味を持っている人のために

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

次のステップでは、関数パラメータとしてT []ではなくIEnumerable を使用します。 –

+0

それをほんの1秒で追加する – JaredPar

+1

インデントと中括弧なしで "using()"ステートメントをスタックできます。複数のをより読みやすくする – data

5

これは型の安全性を強化するのに役立ち、ジェネリック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<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が少ないメモリを使用するように思わ除い2は、ほぼ同じ実行を発見しました。

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 
関連する問題