2009-04-21 17 views
65

.NET'te jeneriklerin temellerini öğreniyorum. Ancak, Hashtable genel eşdeğerini göremiyorum. Lütfen jenerik karma sınıflar oluşturmak için bazı örnek C# kodlarını paylaşın. Sözlük HashTable için yedek bir% 100 damla olmadığınıBir Hashtable'ın genel sürümü nedir?

cevap

91

Dictionary<TKey, TValue>

Not.

NULL'ları işleme biçiminde küçük bir fark var. Var olmayan bir anahtara başvurmaya çalışırsanız, sözlük bir istisna atar. HashTable sadece sıfır döndürecek. Nedeni, değerin 'un yapamayacağı bir değer türü olabileceğidir. Bir Hashtable'da değer her zaman Nesneydi, bu yüzden geri dönen en azından mümkün oldu.

+3

başka fark öğeleri kaldırıldı asla eğer yazılırken, bir 'HashTable' güvenle okuyucu parçacığı keyfi sayısına göre erişilebilir olmasıdır (o iplik değil Birden çok yazar için güvenli. Buna karşılık, Sözlük ', bir eklenti senaryosunda bile birden fazla okuyucu, sıfır yazar dışındaki herhangi bir senaryo için iş parçacığı güvenli değildir. – supercat

+6

Bu iyi bir nokta. Ancak, .NET 4'ün ['ConcurrentDictionary ] 'i (https://msdn.microsoft.com/en-us/library/dd287191%28v=vs.100%29) kullanıma sunduğunu unutmayın.aspx), 'System.Collections.Concurrent' içinde diğer koleksiyonlar gibi iş parçacığı güvenlidir. – J0e3gan

3
+0

diğerini ne zaman kullanabilirim? – johnny

+0

.NET 1.x ile birlikte çalışabilirliği sürdürmeye çalışmadığınız sürece, genel koleksiyonlar üzerinde jenerik olmayan koleksiyonları kullanmanın yararı yoktur. – bdukes

+0

Tam Açıklama için MSDN'deki Genel Koleksiyonları (http://msdn.microsoft.com/en-us/library/ms172181.aspx) Kullanın Bkz. – bdukes

41

Hashtable sınıfının genel sürümü, System.Collections.Generic.Dictionary sınıftır.

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

düzenlenmiştir. –

+2

Meraklı. Microsoft neden bir sözlük ve diğerleri hashtable diyor? Hashtable her zaman jenerikteki sözlükleri okuyana kadar bana gizemli görünüyordu. – johnny

21

Hashtable jenerik versiyon Dictionary<TKey,TValue> sınıf (link) 'dir. İşte oldukça doğrudan bir çeviri sözlük en doğrudan eşdeğer bir Hashtable kullanarak çevrilen bazı örnek kodu (argüman yalınlık sağlamak için kaldırılmıştır Kontrolden)

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

olduğunu. Fakat sorun şu ki, bu aslında jeneriklerin güvenli tip özelliklerinden faydalanmıyor. İkinci fonksiyon aşağıdaki gibi yazılır ve çok daha tip güvenli olması ve hiçbir boks yükü Daha da iyisi

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 edilebilir. İşte (teşekkürler Joel işaret için bu cevapsız) ilgilenenler için

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

Bir sonraki adım, işlev parametreleri için T [] yerine IEnumerable kullanmaktır. –

+0

Yep. Bunu bir saniye içinde eklemek – JaredPar

+1

Bir "girme()" ifadeleri girinti ve kaşlı ayraçlar olmadan istiflenebilir. Birden çok kullanıcının daha okunabilir olmasını sağlar – data

5

, ben genel bir Hashtable sarıcı sınıfını oluşturdu daha da esnek tamamen jenerik versiyon

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

Ve biri, Tip güvenliğinin uygulanması için yararlıdır ve jenerik IDictionary, ICollection ve IEnumerable tip olarak geçirilebilirken, non-generic Hashtable kullanılamaz. Aşağıda uygulama.

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

Ben Sözlük vs bu Hashtable bazı testler yapıp bir dize anahtar ve dize değeri çifti ile kullanıldığında Hashtable'a az bellek kullanımı gibi görünüyor hariç iki, yaklaşık olarak aynı performans bulduk. aşağıdaki gibi benim testin sonuçları şunlardır:

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 
İlgili konular