创建自定义通用集合

Create custom generic collection

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

我为 SortedList<> 实现了 ICollection(KeyValuePair),为 List<> 实现了 ICollection<>,但是我不明白我接下来应该做什么。有人可以给我一个提示,应该如何实现 'store elements in List<> if there are less then 10 of them or in SortedList<> if there are more' 部分?

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

这里有完整的实现。它很长,完全未经测试 :-) 你可以愉快地调试它。

有一些有趣的地方:两个比较器的使用(不是一个好主意),null 的处理是如何完成的(它抛出 NullReferenceException,就像SortedList) 以及各种 AddRemoveClear 中集合之间的切换是如何完成的。请注意,通常 SortedList "hides" 所有直接处理 KeyValuePair<,> 的方法。我选择做同样的事情。其他注意事项:"search" 在 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();
    }
}