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 (2)

  1. Adam says:

    What’s wrong with System.Collections.Generic.Dictionary<TKey, TValue>?

  2. irenake says:

    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…