.NET中NameValueCollection的通用形式

5

.Net提供通用的NameValueCollection或者类似于Dictionary<string,List<T>>的替代方案吗?

比如说:

Person john = new Person();
...
Person vick = new Person();
...

NameValueCollection<Person> stringToPerson = new  NameValueCollection<Person>();
stringToPerson.Add("John",john)
stringToPerson.Add("Vick",vick)

实际上在我的情况下,我被迫依赖于 Dictionary<string,List<Person>>,是否有其他替代方案?

敬礼, Jeez


可能相关:https://dev59.com/vkXRa4cB1Zd3GeqPq1VA - cofiem
5个回答

3
据我所知,BCL中没有内建此类功能。我建议您编写自己的类,该类在内部包装了一个Dictionary<string, List<T>>,并公开适当的方法(例如Add可以将元素添加到给定键的List<T>中)。
例如:
class NameValueCollection<T>
{
    Dictionary<string, List<T>> _dict = new Dictionary<string, List<T>>();

    public void Add(string name, T value)
    {
        List<T> list;
        if (!_dict.TryGetValue(name, out list))
        {
            _dict[name] = list = new List<T>();
        }

        list.Add(value);
    }

    // etc.
}

3
最接近的替代方案可能是ILookup<TKey, TElement>接口。目前,在BCL中实现它的唯一公共类型是不可变的Lookup<TKey, TElement>类,可以使用Enumerable.ToLookup方法创建其实例。如果您想要一个实现该接口的可变类型,则必须自己编写一个;您可以在此处找到一个示例实现。
在您的情况下,您可能需要一个ILookup<string, Person>

是的,但我认为OP想要能够向集合中添加内容;对于此目的而言,Lookup<TKey, TValue>过于限制,因为它是只读的。 - Dan Tao

2

哦,我现在明白你想做什么了。你希望能够在不必每次创建新列表的情况下向Person集合添加内容。这时候就可以使用扩展方法来解决问题!

public static void SafeAdd<TValue>(this IDictionary<TKey, ICollection<TValue>> dict, TKey key, TValue value)
{
     HashSet<T> container;
     if (!dict.TryGetValue(key, out container)) 
     {
         dict[key] = new HashSet<TValue>();
     }
     dict[key].Add(value);
}

Usage:
var names = new Dictionary<string, ICollection<Person>>();
names.SafeAdd("John", new Person("John"));

没问题 Josh,我只是在寻找更好、更易读的东西。 - Jeevan
天啊,我不知道你想要什么。现在我知道了。看看我的答案,我认为你会发现它比重新实现 IDictionary 上的每个方法要容易得多。 - Josh Smeaton

1

没有内置的; 有Lookup<TKey,TValue>,它作为多重映射操作,但它是不可变的。我编写了一个可变的EditableLookup<TKey,TValue>MiscUtil,可能会有所帮助。


0

通用 NameValueCollection

NameValueCollectionDictionary 不同的特点是,一个键可以包含多个元素。

以下代码基于 NameObjectCollectionBase 实现了通用的 NameValueCollection<T>

using System.Collections.Specialized;

namespace System.Collections.Generic
{
    public class NameValueCollection<T> : NameObjectCollectionBase
    {
        private string[] _keys; // Cached keys.
        private T[] _values;    // Cached values.

        // Resets the caches.
        protected void InvalidateCachedArrays()
        {
            _values = null;
            _keys = null;
        }

        // Converts ArrayLit to Array of T elements.
        protected static T[] AsArray(ArrayList list)
        {
            int count = 0;
            if (list == null || (count = list.Count) == 0)
                return (T[])null;
            T[] array = new T[count];
            list.CopyTo(0, array, 0, count);
            return array;
        }

        // Gets all values cache.
        protected ArrayList GetAllValues()
        {
            int count = Count;
            ArrayList arrayList = new ArrayList(count);
            for (int i = 0; i < count; ++i)
            {
                arrayList.AddRange(Get(i));
            }
            return arrayList;
        }

        // Adds single value to collection.
        public void Add(string name, T value)
        {
            InvalidateCachedArrays();
            ArrayList arrayList = (ArrayList)BaseGet(name);
            if (arrayList == null)
            {
                arrayList = new ArrayList(1);
                if (value != null) arrayList.Add(value);
                BaseAdd(name, arrayList);
            }
            else
            {
                if (value == null) return;
                arrayList.Add(value);
            }
        }

        // Adds range of values to collection.
        public void Add(NameValueCollection<T> 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 (prevoious values will be removed).
        public void Set(string name, T value)
        {
            InvalidateCachedArrays();
            BaseSet(name, new ArrayList(1) { value });
        }

        // Set range of values (prevoious values will be removed).
        public void Set(string name, params T[] values)
        {
            InvalidateCachedArrays();
            BaseSet(name, new ArrayList(values));
        }

        // Gets all values that paired with specified key.
        public T[] Get(string name)
        {
            return AsArray((ArrayList)BaseGet(name));
        }

        // Gets all values at the specified index of collection.
        public T[] Get(int index)
        {
            return AsArray((ArrayList)BaseGet(index));
        }

        // Gets string containing the key at the specified index.
        public string GetKey(int index)
        {
            return BaseGetKey(index);
        }

        // 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();
        }

        // All keys that the current collection contains.
        public new 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 = AsArray(GetAllValues());
                return _values;
            }
        }

        // Values at the specefied index.
        public T[] this[int index]
        {
            get
            {
                return Get(index);
            }
            set
            {
                BaseSet(index, new ArrayList(value));
            }
        }

        // Values at the specefied key.
        public T[] this[string name]
        {
            get
            {
                return Get(name);
            }
            set
            {
                BaseSet(name, new ArrayList(value));
            }
        }

        // Enumerates all entries.
        public IEnumerable<KeyValuePair<string, T>> GetAllEntries()
        {
            foreach (string key in Keys)
            {
                foreach (T value in Get(key))
                {
                    yield return new KeyValuePair<string, T>(key, value);
                }
            }
        }
    }
}

使用方法:

NameValueCollection<int> collection = new NameValueCollection<int>();
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.

以上代码实现了主要功能。
这里是实现 NameValueCollection<T> 的完整代码,包含额外的工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接