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

}