如何制作这样的自定义列表/集合

时间:2014-08-04 19:13:08

标签: c# list collections ienumerable

我正在尝试开发一个自定义集合或列表类,它为我提供了以下功能:

Add(MyObject)
Add(MyObject, String)   ' key
Remove(MyObject)
RemoveByKey(String) ' key
RemoveAt(Index)
Count
Clear
Item(Index)
Item(String)    ' key
Contains(MyObject)
ContainsKey(String) ' key
GetEnumerator   ' for-each MyObject

我通过IEnumerable,IList,ICollection进行了搜索,但没有一个能满足我上面的要求。例如,他们都缺少按键(字符串)存储对象。 如何创建这样的集合/列表对象?我注意到符合我要求的最好的东西是系统可用的ListViewItemCollection对象。我希望我能在其中看到编码,以了解它是如何实现对象的存储和检索的。

有人可以帮忙吗?或者引导我学习教程链接。

感谢。

2 个答案:

答案 0 :(得分:1)

这样的类的示例可以是System.Windows.Forms.Control.ControlCollection,它实现为List<KeyValuePair<string,Control>>(实际上Control已包含密钥),this[string]使用普通的for-loop实现(线性)寻找钥匙)。

我们可以通过添加Dictionary并将带有键的每个项目添加到两个集合(List + Dictionary)来帮助加快速度。没有键的项目仅添加到列表中。

编辑:进一步改进可能会使用List<KeyValuePair<string,T>>Dictionary<string,KeyValuePair<int,T>> - 将列表中的索引映射到字典,以便更快地删除。 RemoveAt应检查密钥是否已预设,并将其从字典中删除。 RemoveByKey可以获取内部List.RemoveAt的索引。

基于评论的ADDON: IEnumerable<T>的实施可能如下所示:

class MyObjectList<T>: IEnumerable<T> {
public IEnumerator<T> GetEnumerator() {
    T[] a = items; int n = size;
    for(int i = 0; i < n; i++)
        yield return a[i]; }
IEnumerator IEnumerable.GetEnumerator() {
    return GetEnumerator(); }

......以上是List<T>

的内部结构

ADDON: here you can see my custom ListCoreList created from it(随意使用它)。

答案 1 :(得分:1)

我敢打赌有很多简单的方法可以做到这一点,但这是一种方法。您可以创建一个struct,其中包含每个项目的键和值:

public sealed class Listionary<K, T> : IDictionary<K, T>, IList<T>
{
    private struct ListionaryPair
    {
        public ListionaryPair(T item) : this()
        {
            Item = item;
        }

        public ListionaryPair(K key, T item) : this()
        {
            Key = key;
            Item = item;
        }

        public K Key { get; private set; }
        public T Item { get; private set; }
        public bool HasKey { get; private set; }
    }

    private readonly List<ListionaryPair> list = new List<ListionaryPair>();

(整个HasKey事物允许值类型为Knull引用作为有效键。如果您只想要string个键,则可以用{替换此结构{1}})

然后两个接口分开:

KeyValuePair<string, T>

您可以通过显式实现它们来隐藏丑陋的方法:

    public void Add(T item)
    {
        list.Add(new ListionaryPair(item));
    }

    public void Add(K key, T item)
    {
        list.Add(new ListionaryPair(key, item));
    }

    public void RemoveAt(int index)
    {
        list.RemoveAt(index);
    }

您需要一些辅助方法来按键访问:

    void ICollection<KeyValuePair<K, T>>.CopyTo(KeyValuePair<K, T>[] array, int arrayIndex)
    {
        // code implementing the method
    }

但是如果你把它们弄好了,剩下的就不会那么大了:

    private int IndexOfKey(K key)
    {
        for (int i = 0; i < list.Count; i++)
        {
            var pair = list[i];
            if (pair.HasKey && pair.Key == key)
            {
                return i;
            }
        }

        return -1;
    }

完成每种接口方法需要相当多的编码,但大多数都是简短的。您必须决定是否允许使用相同键的多个项目, public T this[K key] { get { int index = IndexOfKey(key); if (index < 0) { throw new IndexOutOfRangeException(); } return list[index].Item; } set { int index = IndexOfKey(key); if (index < 0) { throw new IndexOutOfRangeException(); } list[index] = new ListionaryPair(key, value); } } 是清除整个集合还是仅清除键控项目等。

此示例中也没有后备IDictionary<,>.Clear(),因此性能可能不会那么好。