创建自定义通用集合

时间:2015-03-22 10:39:06

标签: c# collections

我想创建一个自定义通用集合,如果有少于10个元素,则会在List<>中存储元素;如果有更多元素,则会在SortedList<>中存储元素。

我为ICollection(KeyValuePair)实施了SortedList<>,为ICollection<>实施了List<>,但我无法理解接下来应该做什么。有人可以给我一个提示,如果有少于10个,那么如何在List<>中存储元素,如果有更多&#39;则在SortedList<>中存储元素?

class CustomCollection<T, V> : ICollection<KeyValuePair<T, V>>, ICollection<T>
    {
        private readonly ICollection<T> _list = new List<T>();
        private readonly ICollection<KeyValuePair<T, V>> _sortlist = new SortedList<T, V>();

        public void Add(KeyValuePair<T, V> item)
        {
            _sortlist.Add(item);
        }

        public void Add(T item)
        {
            _list.Add(item);
        }
    }

1 个答案:

答案 0 :(得分:1)

这里有完整的实施。它很长,完全未经测试 :-)你可以玩得很开心。

有一些兴趣点:使用两个Comparer(不是一个好主意),如何处理null(它抛出NullReferenceException,如SortedList)以及各种AddRemoveClear如何在集合之间切换。请注意,通常SortedList“隐藏”直接处理KeyValuePair<,>的所有方法。我选择做同样的事情。其他说明:要在List<>中进行“搜索”,我会进行线性搜索。更聪明(也更快)就是做List.BinarySearch

public class CustomCollection<TKey, TValue> : IDictionary<TKey, TValue>
{
    protected List<KeyValuePair<TKey, TValue>> List { get; set; }
    protected SortedList<TKey, TValue> SortedList { get; set; }

    // Two comparers needed: an EqualityComparer and a Comparer to sort
    // We could simply use the Comparer and compare the result to 0
    // instead of using an EqualityComparer and a Comparer
    protected readonly EqualityComparer<TKey> EqualityComparer = EqualityComparer<TKey>.Default;
    protected readonly Comparer<TKey> Comparer = Comparer<TKey>.Default;

    public int MaxCapacityList { get; protected set; }

    public CustomCollection(int maxCapacityList = 10)
    {
        MaxCapacityList = maxCapacityList;

        if (maxCapacityList > 0)
        {
            List = new List<KeyValuePair<TKey, TValue>>();
        }
        else
        {
            SortedList = new SortedList<TKey, TValue>();
        }
    }

    public bool IsUsingList
    {
        get
        {
            return List != null;
        }
    }

    public void Add(TKey key, TValue value)
    {
        if (IsUsingList)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            if (List.Any(x => EqualityComparer.Equals(x.Key, key)))
            {
                throw new ArgumentException();
            }
        }

        if (IsUsingList && List.Count < MaxCapacityList)
        {
            List.Add(new KeyValuePair<TKey, TValue>(key, value));

            // Only place we need to sort. Only "real" Add method
            List.Sort((x, y) => Comparer.Compare(x.Key, y.Key));
        }
        else
        {
            if (IsUsingList && List.Count == MaxCapacityList)
            {
                SortedList = new SortedList<TKey, TValue>();

                foreach (var kv in List)
                {
                    SortedList.Add(kv.Key, kv.Value);
                }

                List = null;
            }

            SortedList.Add(key, value);
        }
    }

    public bool ContainsKey(TKey key)
    {
        if (IsUsingList)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            if (List.Any(x => EqualityComparer.Equals(x.Key, key)))
            {
                return true;
            }

            return false;
        }

        return SortedList.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get
        {
            if (IsUsingList)
            {
                return List.ConvertAll(x => x.Key);
            }

            return SortedList.Keys;
        }
    }

    public bool Remove(TKey key)
    {
        if (IsUsingList)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            for (int ix = 0; ix < List.Count; ix++)
            {
                if (EqualityComparer.Equals(List[ix].Key, key))
                {
                    List.RemoveAt(ix);
                    return true;
                }
            }

            return false;
        }

        bool result = SortedList.Remove(key);

        if (result && SortedList.Count == MaxCapacityList && MaxCapacityList > 0)
        {
            List = new List<KeyValuePair<TKey, TValue>>();

            foreach (var kv in SortedList)
            {
                List.Add(new KeyValuePair<TKey, TValue>(kv.Key, kv.Value));
            }

            SortedList = null;
        }

        return result;
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        if (IsUsingList)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            for (int i = 0; i < List.Count; i++)
            {
                if (EqualityComparer.Equals(List[i].Key, key))
                {
                    value = List[i].Value;
                    return true;
                }
            }

            value = default(TValue);
            return false;
        }

        return SortedList.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get
        {
            if (IsUsingList)
            {
                return List.ConvertAll(x => x.Value);
            }

            return SortedList.Values;
        }
    }

    public TValue this[TKey key]
    {
        get
        {
            if (IsUsingList)
            {
                if (key == null)
                {
                    throw new ArgumentNullException();
                }

                for (int ix = 0; ix < List.Count; ix++)
                {
                    if (EqualityComparer.Equals(List[ix].Key, key))
                    {
                        return List[ix].Value;
                    }
                }

                throw new KeyNotFoundException();
            }

            return SortedList[key];
        }
        set
        {
            if (IsUsingList)
            {
                if (key == null)
                {
                    throw new ArgumentNullException();
                }

                for (int ix = 0; ix < List.Count; ix++)
                {
                    if (EqualityComparer.Equals(List[ix].Key, key))
                    {
                        List[ix] = new KeyValuePair<TKey, TValue>(key, value);
                        return;
                    }
                }

                Add(key, value);

                return;
            }

            SortedList[key] = value;
        }
    }

    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        Add(item.Key, item.Value);
    }

    public void Clear()
    {
        if (IsUsingList)
        {
            List.Clear();
        }
        else
        {
            if (MaxCapacityList > 0)
            {
                List = new List<KeyValuePair<TKey, TValue>>();
                SortedList = null;
            }
            else
            {
                SortedList.Clear();
            }
        }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
    {
        if (IsUsingList)
        {
            if (item.Key == null)
            {
                throw new ArgumentNullException();
            }

            return List.Any(x => EqualityComparer.Equals(x.Key, item.Key));
        }

        return ((ICollection<KeyValuePair<TKey, TValue>>)SortedList).Contains(item);
    }

    void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        if (IsUsingList)
        {
            List.CopyTo(array, arrayIndex);
            return;
        }

        ((ICollection<KeyValuePair<TKey, TValue>>)SortedList).CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return IsUsingList ? List.Count : SortedList.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        if (IsUsingList)
        {
            if (item.Key == null)
            {
                throw new ArgumentNullException();
            }

            for (int ix = 0; ix < List.Count; ix++)
            {
                if (EqualityComparer.Equals(List[ix].Key, item.Key))
                {
                    var comparer2 = EqualityComparer<TValue>.Default;

                    if (comparer2.Equals(List[ix].Value, item.Value))
                    {
                        List.RemoveAt(ix);
                        return true;
                    }

                    return false;
                }
            }

            return false;
        }

        bool result = ((ICollection<KeyValuePair<TKey, TValue>>)SortedList).Remove(item);

        if (result && SortedList.Count == MaxCapacityList && MaxCapacityList > 0)
        {
            List = new List<KeyValuePair<TKey, TValue>>();

            foreach (var kv in SortedList)
            {
                List.Add(new KeyValuePair<TKey, TValue>(kv.Key, kv.Value));
            }

            SortedList = null;
        }

        return result;
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return IsUsingList ? List.GetEnumerator() : SortedList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        // Chained to the other GetEnumerator()
        return GetEnumerator();
    }
}