目录
介绍
背景
类定义
基本方法
属性
集合枚举
用法
下载源代码 - 4.6 KB
介绍内置在mscorlib中的NameValueCollection实现是一个类似于Dictionary的集合,但NameValueCollection可以有重复的键,而Dictionary不能。元素可以通过索引和键获得。这个集合的特别之处在于,一个键可以包含多个元素,并且允许null作为键或值。但是有一个小问题。NameValueCollection假定字符串用作键和值。那么如果你想存储任何类型的值,而不仅仅是字符串呢?? 当然,您可以在每次获取值时将文本转换为所需的类型,但是这里有三个重要的限制:
- 转换的处理开销;
- 并非所有类型都支持与字符串的转换;
- 不保留对原始对象的引用。
NameValueCollection集合基于NameObjectCollectionBase——关联字符串键和对象值集合的基类,其中包含访问值的基本方法。接口IDictionary,IEnumerable在类中实现为额外的可用性。
类定义第一次,定义包含键和值的类及其成员。私有字段将包含指定数组中的缓存数据。该InvalidateCachedArrays方法将重置缓存并在每次数据更改时调用。
public partial class NameValueCollection : NameObjectCollectionBase
{
private string[] _keys; // Cached keys.
private T[] _values; // Cached values.
// Resets the caches.
protected void InvalidateCachedArrays()
{
_values = null;
_keys = null;
}
}
下一步,是时候添加可以使用基类方法获取、设置和删除集合中数据的类方法了。
Add和Set方法将接收到的值放入与指定键配对的列表中。
public partial class NameValueCollection
{
// Adds single value to collection.
public void Add(string name, T value)
{
InvalidateCachedArrays();
List list = BaseGet(name) as List;
if (list == null)
{
list = new List(1) {value};
BaseAdd(name, list);
}
else
{
if (value == null) return;
list.Add(value);
}
}
// Adds range of values to collection.
public void Add(NameValueCollection collection)
{
InvalidateCachedArrays();
int count = collection.Count;
for (int i = 0; i < count; i++)
{
string key = collection.GetKey(i);
T[] values = collection.Get(i);
foreach (var value in values)
{
Add(key, value);
}
}
}
// Set single value (previous values will be removed).
public void Set(string name, T value)
{
InvalidateCachedArrays();
BaseSet(name, new List(1){value});
}
// Set range of values (previous values will be removed).
public void Set(string name, params T[] values)
{
InvalidateCachedArrays();
BaseSet(name, new List(values));
}
}
GetKey和Get方法返回请求的键和与键值关联的数组。无论它们配对的键如何,GetAllValues都返回所有值,这些方法在将来很有用。
public partial class NameValueCollection
{
// Gets all values cache.
protected T[] GetAllValues()
{
int count = Count;
List list = new List(count);
for (int i = 0; i < count; ++i)
{
list.AddRange(Get(i));
}
return list.ToArray();
}
// Gets all values that paired with specified key.
public T[] Get(string name)
{
return ((List)BaseGet(name)).ToArray();
}
// Gets all values at the specified index of collection.
public T[] Get(int index)
{
return ((List)BaseGet(index)).ToArray();
}
// Gets string containing the key at the specified index.
public string GetKey(int index)
{
return BaseGetKey(index);
}
}
Clear和Remove方法从集合中删除值。
public partial class NameValueCollection
{
// Removes values from the specified key.
public void Remove(string name)
{
InvalidateCachedArrays();
BaseRemove(name);
}
// Removes all data from the collection.
public void Clear()
{
InvalidateCachedArrays();
BaseClear();
}
}
快完成了!为了使这个集合更易于使用,添加属性是一个好主意。Keys和Values属性尝试返回缓存数据并在缓存失效时对其进行更新。
public partial class NameValueCollection
{
// All keys that the current collection contains.
public string[] Keys
{
get
{
if (_keys == null)
_keys = BaseGetAllKeys();
return _keys;
}
}
// All values that the current collection contains.
public T[] Values
{
get
{
if (_values == null)
_values = GetAllValues();
return _values;
}
}
// Values at the specified index.
public T[] this[int index]
{
get
{
return Get(index);
}
set
{
BaseSet(index, new List(value));
}
}
// Values at the specified key.
public T[] this[string name]
{
get
{
return Get(name);
}
set
{
BaseSet(name, new List(value));
}
}
}
嵌入类Enumerator将负责枚举集合中的所有键值对。该GetAllEntries方法返回枚举器使用的所有键值对。
public partial class NameValueCollection
{
// Enumerates all entries.
protected IEnumerable GetAllEntries()
{
return
from key in Keys
from value in Get(key)
select new KeyValuePair(key, value);
}
// The enumerator that can enumerate all entries in the collection.
private class Enumerator : IEnumerator, IDictionaryEnumerator
{
// Enumerate all entries in collection.
private readonly IEnumerator _enumerator;
// Initialize the enumerator.
public Enumerator(NameValueCollection collection)
{
IEnumerable entries =
collection.GetAllEntries().ToArray();
_enumerator = entries.GetEnumerator();
}
// Returns the element of the collection corresponding
// to the current position of the enumerator.
KeyValuePair IEnumerator.Current
{
get { return _enumerator.Current; }
}
// Returns the object of the collection corresponding
// to the current position of the enumerator.
object IEnumerator.Current
{
get
{
IEnumerator enumerator = ((IEnumerator) _enumerator);
return enumerator.Current;
}
}
// Gets the key of the current dictionary entry.
object IDictionaryEnumerator.Key
{
get
{
IEnumerator enumerator =
((IEnumerator) this);
return enumerator.Current.Key;
}
}
// Gets the value of the current dictionary entry.
object IDictionaryEnumerator.Value
{
get
{
IEnumerator enumerator =
((IEnumerator) this);
return enumerator.Current.Value;
}
}
// Gets both the key and the value of the current dictionary entry.
DictionaryEntry IDictionaryEnumerator.Entry
{
get
{
IEnumerator enumerator =
((IEnumerator) this);
return new DictionaryEntry(enumerator.Current.Key,
enumerator.Current.Value);
}
}
// Move enumerator to the next entry.
public bool MoveNext()
{
return _enumerator.MoveNext();
}
// Reset enumerator to start position.
public void Reset()
{
_enumerator.Reset();
}
// Unused dispose pattern.
public void Dispose()
{
}
}
}
最后一步是实现指定的接口IDictionary和IEnumerable。一些方法和属性是显式实现的,也就是说,它们的使用需要预先转换为适当的接口类型。
public partial class NameValueCollection :
IDictionary,
IEnumerable
{
// Gets an collection containing the values.
ICollection IDictionary.Keys => Keys;
// Gets an collection containing the values.
ICollection IDictionary.Values => Values;
// Indicates whether the collection is read-only.
public new bool IsReadOnly => base.IsReadOnly;
// Indicates whether the collection contains a fixed number of items.
public bool IsFixedSize => false;
// Determines whether the collection contains an element with the specified key.
bool IDictionary.Contains(object key)
{
return key is string s && Keys.Contains(s);
}
// Adds an object with the specified key to the colletion.
void IDictionary.Add(object key, object value)
{
Add((string)key, (T)value);
}
// Removes the element with the specified key from the collection.
void IDictionary.Remove(object key)
{
Remove((string)key);
}
// Gets or sets the item with the specified key.
object IDictionary.this[object key]
{
get
{
return Get((string)key);
}
set
{
if (value is IEnumerable collection)
{
Set((string)key, (T[])collection.ToArray());
}
else
{
Set((string)key, (T)value);
}
}
}
// The three methods below return an enumerator for current collection.
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(this);
}
public override IEnumerator GetEnumerator()
{
return new Enumerator(this);
}
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return new Enumerator(this);
}
}
NameValueCollection collection = new NameValueCollection();
collection.Add("a", 123);
collection.Add("a", 456); // 123 and 456 will be inserted into the same key.
collection.Add("b", 789); // 789 will be inserted into another key.
int[] a = collection.Get("a"); // contains 123 and 456.
int[] b = collection.Get("b"); // contains 789.
在本文的最后,我想说的是,上面的代码实现了基本功能。在附件中,您将找到完整的源代码,其中包含文章中未包含的一些附加扩展。
https://www.codeproject.com/Articles/5323395/A-Generic-Form-of-the-NameValueCollection