如何在C#中覆盖List <t>的Add方法?</t>

时间:2009-02-24 02:07:59

标签: c# generics inheritance collections

我目前正在寻找自己的收藏品,这就像一个普通的清单,除了它只能容纳10件物品。如果在列表中已有10个项目时添加了项目,则在添加新项目之前将删除第一个项目。

我想要做的是创建一个扩展System.Collections.Generic.List<T>的类,然后修改Add(T item)方法以包含在必要时删除第一个项目的功能。

11 个答案:

答案 0 :(得分:65)

您还可以通过

实现添加方法
public new void Add(...)

在派生类中隐藏现有的添加并引入您的功能。

编辑:粗略轮廓......

class MyHappyList<T> : List<T>
{
    public new void Add(T item)
    {
        if (Count > 9)
        {
            Remove(this[0]);
        }

        base.Add(item);
    }
}

只是一个注释,认为它是隐含的,但您必须始终按实际类型引用您的自定义列表,而不是基本类型/接口,因为隐藏方法仅适用于您的类型和其他派生类型。

答案 1 :(得分:43)

首先,您不能覆盖Add并且仍然具有针对List的多态性,这意味着如果您使用new关键字并且您的类被强制转换为List,则不会调用您的新Add方法。 / p>

其次,我建议您查看Queue类,因为您要做的更多的是队列而不是列表。该类针对您想要做的事情进行了优化,但没有任何类型的大小限制器。

如果你真的希望某些东西像List一样工作但是像最大尺寸的Queue一样工作,我建议你实现IList并保留一个Queue实例来存储你的元素。

例如:

public class LimitedQueue<T> : IList<T>
{
  public int MaxSize {get; set;}
  private Queue<T> Items = new Queue<T>();
  public void Add(T item)
  {
    Items.Enqueue(item);
    if(Items.Count == MaxSize)
    {
       Items.Dequeue();
    }
  }
  // I'll let you do the rest
}

答案 2 :(得分:26)

您无法覆盖Add(),它不是虚方法。改为从IList派生并使用私有Queue成员进行实现。

答案 3 :(得分:17)

您可以扩展System.Collections.ObjectModel.Collection并覆盖InsertItem方法以获得所需的行为,并且它还实现了IList

答案 4 :(得分:8)

您可以编写一个实现IList<T>的类,该类包含内部List<T>并编写您自己的方法。

答案 5 :(得分:5)

我能做的最好就是:

class MostRecentList<T> : System.Collections.Generic.List<T> {
        private int capacity;

        public MostRecentList(int capacity) : base() {
            this.capacity = capacity;
        }

        public new void Add(T item) {
            if (base.Count == capacity) {
                base.RemoveAt(0);
            }
            base.Add(item);
        }
}

由于add()方法未标记为虚拟。

答案 6 :(得分:3)

您对要求的描述听起来像Circular Buffer

我实现了自己的 - 类似于this implementation on CodePlex,除了我的实现IList<T>

其他一些答案建议使用Queue<T> - 但这并不完全相同,因为它只允许进行FIFO访问。

一般来说,不建议从List<T>派生 - 而是从Collection<T>派生,并实施您需要的任何其他内容。但是对于循环缓冲区,使用私有数组可能更合适,而不是像CodePlex实现那样从Collection<T>派生。

答案 7 :(得分:1)

您可以查看C5集合库。它们具有ArrayList&lt; T&gt;。实现IList&lt; T&gt;并有一个虚拟的Add方法。 C5集合库是一个很棒的列表,队列,堆栈等集合......你可以在这里找到C5库:

http://www.itu.dk/research/c5/

答案 8 :(得分:1)

阅读Liskov Substitution Principle,您的收藏品是扩展列表<T>的非常差的候选者,它甚至不是实施IList <T>的绝佳选择。

此数据需要哪些读取模式?如果您只需要查看所有当前条目,那么实现IEnumerable <T>和Add(T)方法应该足以开始。

然后可以通过私有队列(或者Deque会更好,但是这样的集合需要一些其他集合API,我不建议你自己尝试实现一个)来实现这一点,你在Add(Enqueue()期间将它排队()如果需要保持大小,可以使用Dequeue。

请注意,实现IEnumerable并提供Add方法意味着如果需要,您仍然可以使用Collection初始化语法。

如果您需要随机访问这些值,那么实现索引器可能是一个好主意,但如果没有更多关于该问题的上下文,我不会看到这会给您带来什么好处。

答案 9 :(得分:0)

您可以尝试扩展System.Collections.ObjectModel.Collection<T>,这更加灵活。然后,您可以覆盖受保护的成员InsertItemSetItem,以自定义集合的行为。

答案 10 :(得分:0)

如果使用显式接口实现,实际上是可以做到的。

public class SampleClass<T> : IList<T>
{
    ...
    void IList<T>.Add(T item) { ... }
    public int Add(T item) { ... }
    ...
}

然后调用,就像

IList<T> sample = new SampleClass();
int index = sample.Add(someStuffGoesHere); // new Add method is called