简体   繁体   中英

Create custom generic collection

I want to create a custom generic collection, which will store elements in List<> if there are less then 10 of them or in SortedList<> if there are more.

I implemented ICollection(KeyValuePair) for SortedList<> and ICollection<> for List<> , however I can't understand what should I do next. Could someone please give me a hint, how should implement the part '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);
        }
    }

Here there is the full implementation. It is quite long, and totally untested :-) You can have fun debugging it.

There are some points of interest: the use of the two Comparer(s) (not a good idea), how the handling of null is done (it throws NullReferenceException , like the SortedList) and in the various Add , Remove , Clear how the switch between collections is done. Note that in general SortedList "hides" all the methods that handle directly the KeyValuePair<,> . I selected to do the same. Other note: to "search" in the List<> I do a linear search. Smarter (and faster) would be to do a 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();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM