He estado aprendiendo los conceptos básicos de los genéricos en .NET. Sin embargo, no veo el equivalente genérico de Hashtable
. Por favor comparta un ejemplo de código C# para crear clases de hashtable genéricas.¿Cuál es la versión genérica de una Hashtable?
Respuesta
Tenga en cuenta que no es un diccionario caída de 100% en el reemplazo para HashTable.
Hay una ligera diferencia en la forma en que manejan NULL. El diccionario generará una excepción si intenta hacer referencia a una clave que no existe. El HashTable simplemente devolverá nulo. La razón es que el valor puede ser un tipo de valor, que no puede ser nulo. En una Hashtable, el valor siempre era Object, por lo que volver al valor nulo era al menos posible.
La versión genérica de System.Collection.Hashtable
es System.Collections.Generic.Dictionary<TKey, TValue>
.
¿Cuándo usaría uno sobre el otro? – johnny
A menos que intente mantener la interoperabilidad con .NET 1.x, no hay beneficio en el uso de las colecciones no genéricas en las colecciones genéricas. – bdukes
Consulte Cuándo usar colecciones genéricas (http://msdn.microsoft.com/en-us/library/ms172181.aspx) en MSDN para obtener la explicación completa – bdukes
La versión genérica de la clase Hashtable es System.Collections.Generic.Dictionary clase.
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);
}
editado para vincular la versión de MSDN Loband. –
Curioso. ¿Por qué Microsoft lo llama un diccionario y otros una tabla hash? Hashtable siempre me pareció misterioso hasta que leí sobre diccionarios en genéricos. – johnny
La versión genérica de un Hashtable es la clase Dictionary<TKey,TValue>
(link). Aquí algunos ejemplos de código traducido del uso de una tabla hash en el equivalente más directa de diccionario (comprobación de argumentos retirado por razones de brevedad)
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;
}
Esa es una traducción bastante directa. Pero el problema es que esto en realidad no aprovecha el tipo de características de seguridad de los genéricos. La segunda función se puede escribir de la siguiente manera y ser mucho más seguro y tipo inccur ninguna sobrecarga de boxeo
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;
}
aún mejor. Aquí hay una versión completamente genérico
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;
}
Y uno que es aún más flexible, más (gracias a Joel por señalar que se perdió este)
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;
}
Para aquellos que estén interesados, he creado una clase contenedora Hashtable genérico, que es útil para aplicar la seguridad del tipo y se puede pasar como IDictionary genérico, tipo ICollection e IEnumerable, mientras que el Hashtable no genérico no puede. A continuación está la implementación.
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<TKey, TValue>"</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<TKey, TValue>"</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;
}
}
}
}
He hecho algunas pruebas de este Hashtable vs diccionario y encontró los dos realizan sobre la misma cuando se utiliza con un par cadena de clave y valor de cadena, a excepción de la tabla hash parece usar menos memoria. Los resultados de mi prueba son como sigue:
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
- 1. ¿Cuál es la diferencia entre una Hashtable y Properties?
- 2. ¿Cuál es la mejor manera de convertir una colección no genérica en una colección genérica?
- 3. ¿Cuál es la diferencia entre KeyValuePair y Hashtable en .NET?
- 4. Cuál es la diferencia principal entre Dictionary y Hashtable
- 5. ¿Cuál es la diferencia entre Hashtable y Dictionary?
- 6. versión genérica de la Enum.Parse en C#
- 7. patrón para exponer versión no genérica de interfaz genérica
- 8. ¿Cuál es la diferencia entre "Versión heredada" y "Versión estable"?
- 9. Implementación genérica de System.Runtime.Caching.MemoryCache
- 10. ¿cuál es mi versión HAProxy?
- 11. ¿Cuál es la forma adecuada de escribir con fuerza el retorno de una función genérica?
- 12. ¿Por qué no hay una versión genérica de HybridDictionary?
- 13. ¿Cuál es la mejor manera de usar la versión de archivo y la versión de ensamblaje?
- 14. ¿Cuánta memoria usa una Hashtable?
- 15. ¿Cuál es la versión de cron de Windows?
- 16. ¿Cuál es la versión de Android de HTML's TextArea?
- 17. ¿Cuál es la versión C++ de ArrayList de Java?
- 18. ¿Cuál es la versión de C++ de Guid.NewGuid()?
- 19. ¿Cuál es la versión de oráculo más ligera?
- 20. ¿hashtable de actualización por otra hashtable?
- 21. ¿Cuál es la versión del GIL de C#?
- 22. ¿cuál es la versión correcta de Eclipse para ColdFusion?
- 23. ¿Cuál es la versión de JScript que está en IE9?
- 24. ¿Cuál es la versión C# del InputDialog de VB.net?
- 25. ¿Cuál es la última versión de WebSphere MQ Client?
- 26. Ventajas de HashTable
- 27. ¿Cuál es el significado de "programación genérica" en C++?
- 28. cuál es la diferencia entre rama de versión por área de trabajo y por última versión
- 29. Inicializar una matriz genérica de Java de tipo genérico
- 30. ¿Cuál es la diferencia entre Microsoft.Office.Interop. * Versión 12 y 14?
Otra diferencia es que si los artículos no se eliminan, un 'HashTable' se puede acceder de manera segura por un número arbitrario de hilos lector mientras está siendo escrito (que no es hilo -seguro para múltiples escritores). Por el contrario, 'Dictionary' no es seguro para subprocesos para ningún otro escenario que no sean varios lectores, cero escritores, incluso en un escenario de solo agregado. –
supercat
Ese es un buen punto. Sin embargo, tenga en cuenta que .NET 4 introdujo ['ConcurrentDictionary'] (https://msdn.microsoft.com/en-us/library/dd287191%28v=vs.100%29.aspx), que es seguro para subprocesos al igual que otras colecciones en 'System.Collections.Concurrent'. –
J0e3gan