SYSK 271: A Better (?) NameValueCollection Class
In spite of its generic name-value collection name, the System.Collections.Specialized.NameValueCollection class only deals with string keys and string values.
In most cases, a string key is just fine… but to force the value to being of string type only, in my opinion, is quite limiting.
So, I’ve created my own version of this class that deals with a string key, and any value.
Warning: the code below has not been tested! Use at your own risk.
// One key -> one or more values
[Serializable()]
public class NameValueCollection : System.Collections.Specialized.NameObjectCollectionBase
{
#region ctors
public NameValueCollection() : base()
{
// Using the default case-insensitive hash code provider
}
public NameValueCollection(NameValueCollection items) : base()
{
Add(items);
}
public NameValueCollection(int capacity) : base(capacity)
{
}
public NameValueCollection(System.Collections.IEqualityComparer equalityComparer) : base( equalityComparer)
{
}
public NameValueCollection(int capacity, System.Collections.IEqualityComparer equalityComparer)
: base(capacity, equalityComparer)
{
}
public NameValueCollection(int capacity, NameValueCollection items) : base(capacity)
{
if (items == null)
throw new ArgumentNullException("items");
Add(items);
}
protected NameValueCollection(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{
}
#endregion
#region Public methods
public void Add(NameValueCollection items)
{
if (items == null)
throw new ArgumentNullException("items");
int itemCount = items.Count;
for (int i = 0; i < itemCount; i++)
{
string key = items.GetKey(i);
object value = items[i];
if (value != null)
{
if (value.GetType().IsArray == true)
{
object[] values = value as object[];
for (int j = 0; j < values.Length; j++)
Add(key, values[j]);
}
else
{
Add(key, value);
}
}
else
{
Add(key, null);
}
}
}
public virtual void Clear()
{
CheckReadOnly();
BaseClear();
}
public void CopyTo(Array destination, int index)
{
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Rank != 1)
throw new ArgumentException("Destination must be a one-dimensional array");
if (index < 0)
throw new ArgumentOutOfRangeException("index", "Starting index must be zero or greater");
int n = this.Count;
if ((destination.Length - index) < n)
throw new ArgumentException(string.Format("Destination array is too small to hold {0} elements", n));
for (int i = 0; i < n; i++)
{
destination.SetValue(this[i], i + index);
}
}
public virtual void Add(object name, object value)
{
if (name == null)
throw new ArgumentNullException("name");
Add(name.ToString(), value);
}
public virtual void Add(string name, object value)
{
CheckReadOnly();
System.Collections.ArrayList values = BaseGet(name) as System.Collections.ArrayList;
if (values == null)
{
// New key => add new key element with single value
values = new System.Collections.ArrayList(1);
if (value != null)
values.Add(value);
BaseAdd(name, values);
}
else
{
// Existing key => append value to the list of values
if (value != null)
values.Add(value);
}
}
public virtual void Remove(string name)
{
BaseRemove(name);
}
public object this[string name]
{
get
{
object result = null;
System.Collections.ArrayList values = BaseGet(name) as System.Collections.ArrayList;
if (values != null)
{
if (values.Count == 1)
result = values[0];
else
result = values.ToArray();
}
return result;
}
set
{
CheckReadOnly();
System.Collections.ArrayList values = new System.Collections.ArrayList(1);
values.Add(value);
BaseSet(name, values);
}
}
public object this[int index]
{
get { return this[GetKey(index)]; }
}
public virtual string GetKey(int index)
{
return BaseGetKey(index);
}
public virtual string[] AllKeys
{
get { return BaseGetAllKeys(); }
}
#endregion
#region Internal helper methods
private void CheckReadOnly()
{
if (IsReadOnly)
throw new NotSupportedException("This collection instance is read-only");
}
#endregion
}
Comments
Anonymous
January 22, 2007
What's wrong with System.Collections.Generic.Dictionary<TKey, TValue>?Anonymous
January 22, 2007
If you try to add a second (third, etc.) value for same key, you get an exception. Take a look at the System.Collections.Specialized.NameValueCollection class to see its behavior...