Tôi đã học được những điều cơ bản về Generics trong .NET. Tuy nhiên, tôi không thấy tương đương chung của Hashtable
. Vui lòng chia sẻ một số mã C# mẫu để tạo các lớp hashtable chung.Phiên bản chung của Hashtable là gì?
Trả lời
Lưu ý rằng từ điển không thay thế 100% cho HashTable.
Có một sự khác biệt nhỏ trong cách họ xử lý NULL. Từ điển sẽ ném một ngoại lệ nếu bạn cố gắng tham chiếu một khóa không tồn tại. HashTable sẽ trả về null. Lý do là giá trị có thể là loại giá trị, trong đó không thể là rỗng. Trong một Hashtable giá trị luôn là Object, vì vậy trả về null là ít nhất có thể.
Phiên bản chung của System.Collection.Hashtable
là System.Collections.Generic.Dictionary<TKey, TValue>
.
khi nào tôi sử dụng cái này qua cái kia? – johnny
Trừ khi bạn đang cố gắng duy trì khả năng tương tác với .NET 1.x, không có lợi ích gì khi sử dụng các bộ sưu tập không chung chung trên các bộ sưu tập chung chung. – bdukes
Xem Thời điểm Sử dụng Bộ sưu tập Chung (http://msdn.microsoft.com/en-us/library/ms172181.aspx) trên MSDN để được giải thích đầy đủ – bdukes
Phiên bản chung của lớp Hashtable là lớp System.Collections.Generic.Dictionary.
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);
}
được chỉnh sửa để liên kết phiên bản loband MSDN. –
Tò mò. Tại sao Microsoft gọi nó là một từ điển và những người khác là một hashtable? Hashtable luôn luôn có vẻ bí ẩn với tôi cho đến khi tôi đọc về từ điển trong Generics. – johnny
Phiên bản chung của một Hashtable là lớp Dictionary<TKey,TValue>
(link). Dưới đây là một số mẫu mã dịch từ việc sử dụng một Hashtable vào tương đương trực tiếp nhất của từ điển (lập luận việc kiểm tra loại bỏ vì lợi ích ngắn gọn)
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;
}
Đó là một bản dịch khá trực tiếp. Nhưng vấn đề là điều này không thực sự tận dụng lợi thế của các loại tính năng an toàn của generics. Chức năng thứ hai có thể được viết như sau và có nhiều loại an toàn hơn và không có chi phí đấm bốc nào
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;
}
Thậm chí tốt hơn. Dưới đây là một phiên bản hoàn toàn generic
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;
}
Và một mà thậm chí còn tiếp tục linh hoạt (nhờ Joel để chỉ ra tôi đã bỏ lỡ này)
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;
}
Đối với những người quan tâm, tôi đã tạo ra một lớp wrapper Hashtable chung chung, đó là hữu ích cho việc thực thi an toàn kiểu và có thể được chuyển thành kiểu IDictionary, ICollection và IEnumerable chung, trong khi Hashtable không chung chung không thể. Dưới đây là việc thực hiệ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;
}
}
}
}
Tôi đã thực hiện một số kiểm tra về Hashtable so với từ điển này và tìm thấy hai hoạt động giống nhau khi được sử dụng với một chuỗi khóa và chuỗi giá trị chuỗi, ngoại trừ Hashtable dường như sử dụng ít bộ nhớ hơn. Các kết quả thử nghiệm của tôi như sau:
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. Enum là khóa của HashTable
- 2. Phiên bản Android của TextArea HTML là gì?
- 3. MySQL: Phiên bản ngược lại của LIKE là gì?
- 4. Phiên bản MR hiện thời là gì?
- 5. id phiên bản nối tiếp là gì?
- 6. Điểm chung của loại chung trong foreach là gì?
- 7. Điểm chung của lớp học là gì?
- 8. Tại sao không có phiên bản chung của HybridDictionary?
- 9. Ưu điểm của HashTable
- 10. Phiên bản không chung của các lớp và giao diện chung
- 11. Cài đặt chung của System.Runtime.Caching.MemoryCache
- 12. Sự khác nhau giữa Hashtable và Properties là gì?
- 13. Sự khác biệt giữa Hashtable và Từ điển là gì?
- 14. Mục đích của phiên JMS là gì?
- 15. Phạm vi của phiên HTTP là gì?
- 16. Sự khác nhau giữa Phiên bản và 'Phiên bản thời gian chạy' trong .Net là gì?
- 17. "CLR20r3" có nghĩa là gì? (Phiên bản của clr là nó)
- 18. Sự khác biệt giữa "Phiên bản cũ" và "Phiên bản ổn định" là gì?
- 19. Phiên bản WebSphere MQ Client mới nhất là gì?
- 20. Sử dụng làm phiên bản ban đầu là gì?
- 21. Các số phiên bản AccuRev khác nhau là gì?
- 22. Phiên bản ổn định cho jasperreports-maven-plugin là gì?
- 23. Dòng phiên bản Python có nghĩa là gì?
- 24. Điều gì có nghĩa là ASP.net Phiên bản 2.0?
- 25. Lỗi cấu hình Magento chung của bạn là gì?
- 26. phiên bản java gì là cần thiết cho JUnit 4,8
- 27. "RTMREL" có nghĩa là gì trong phiên bản phần mềm?
- 28. Công nghệ đằng sau bing là gì? Phiên bản riêng của thuật toán giảm bản đồ hoặc cái gì khác?
- 29. "Loại ArrayList không chung chung" nghĩa là gì?
- 30. Sử dụng các đối tượng chung của Lisp CLOS làm khóa trong một hashtable?
Một khác biệt nữa là nếu các mục không bao giờ bị xóa, một 'HashTable' có thể được truy cập một cách an toàn bởi một số chủ đề độc giả trong khi nó đang được viết (nó không phải là chủ đề an toàn cho nhiều nhà văn). Ngược lại, từ điển 'không an toàn cho bất kỳ kịch bản nào khác ngoài nhiều độc giả, không phải là người viết, ngay cả trong một kịch bản chỉ bổ sung. –
supercat
Đó là một điểm tốt. Tuy nhiên, lưu ý rằng .NET 4 đã giới thiệu ['ConcurrentDictionary'] (https://msdn.microsoft.com/en-us/library/dd287191%28v=vs.100%29.aspx), vốn an toàn như các bộ sưu tập khác trong 'System.Collections.Concurrent'. –
J0e3gan