Как переопределить List <T> Добавить метод в С#?

В настоящее время я ищу свою собственную коллекцию, которая будет похожа на обычный список, за исключением того, что она будет содержать только 10 элементов. Если элемент был добавлен, когда в списке было уже 10 элементов, первый элемент будет удален до добавления нового элемента.

Я хочу создать класс, который расширяет System.Collections.Generic.List<T>, а затем изменяет метод Add(T item), чтобы включить функциональность, которая удаляет первый элемент, если это необходимо.

Ответ 1

Во-первых, вы не можете переопределить Add и по-прежнему иметь полиморфизм против List, что означает, что если вы используете новое ключевое слово и ваш класс как List, ваш новый метод Add не будет вызываться.

Во-вторых, я предлагаю вам изучить класс Queue, поскольку то, что вы пытаетесь сделать, это скорее очередь, чем список, Класс оптимизирован именно для того, что вы хотите сделать, но не имеет какого-либо ограничителя размера.

Если вы действительно хотите, чтобы что-то действовало как List, но работало как очередь с максимальным размером, я предлагаю вам реализовать IList и сохранить экземпляр очереди для хранения ваших элементов.

Например:

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

Вы также можете реализовать метод добавления с помощью

public new void Add(...)

в производном классе, чтобы скрыть существующее добавление и ввести ваши функции.

Изменить: грубая схема...

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

        base.Add(item);
    }
}

Просто заметите, что это подразумевалось, но вы всегда должны ссылаться на свой собственный список по фактическому типу, а не по базовому типу/интерфейсу, поскольку метод скрытия доступен только для вашего типа и других производных типов.

Ответ 3

Вы не можете переопределить Add(), это не виртуальный метод. Выведите из IList вместо этого и используйте частный член очереди для реализации.

Ответ 4

Вы можете расширить System.Collections.ObjectModel.Collection и переопределить метод InsertItem, чтобы получить нужное поведение, а также реализует IList

Ответ 5

Вы можете просто написать класс, который реализует IList<T>, который содержит внутренний List<T> и записывает ваши собственные методы.

Ответ 6

Похоже, что я могу это сделать:

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() не помечен как виртуальный.

Ответ 7

Ваше описание вашего требования звучит как Круговой буфер.

Я реализовал свою собственную - аналогичную эту реализацию в CodePlex, за исключением того, что моя реализует IList<T>.

Некоторые другие ответы предполагают использование Queue<T> - но это не совсем то же самое, поскольку он позволяет только доступ к FIFO.

Как правило, не рекомендуется выводить из List<T> - вместо этого выводить из Collection<T> и внедрять любые дополнительные вещи, которые вам нужны. Но для кругового буфера, вероятно, более целесообразно использовать частный массив, а не получать из Collection<T>, как реализация CodePlex.

Ответ 8

Вы можете посмотреть библиотеку коллекции C5. Они имеют ArrayList <T> который реализует IList <T> и иметь виртуальный метод Add. Библиотека коллекции C5 представляет собой удивительную коллекцию списков, очередей, стеков и т.д. Здесь вы можете найти библиотеку C5:

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

Ответ 9

Прочитайте Принцип замены Лискова, ваша коллекция - очень плохой кандидат на расширение List <T>, это даже не отличный кандидат на реализацию IList <T>.

Какие шаблоны считывания необходимы для этих данных? Если вам нужно всего лишь просмотреть все текущие записи, то для начала использования IEnumerable <T> и метода Add (T) должно быть достаточно.

Затем это может быть реализовано частной Queue (или Deque будет лучше, но для такой коллекции потребуется некоторый другой API коллекций, и я не предлагаю вам попробовать его реализовать самостоятельно), к которому вы добавили Enqueue() во время добавления ( с Dequeue, если необходимо для поддержания размера).

Обратите внимание: реализация IEnumerable и предоставление метода Add означает, что при необходимости вы можете использовать синтаксис инициализатора коллекции.

Если вам нужен произвольный доступ к значениям, тогда внедрение индексатора может быть хорошей идеей, но я не вижу, какую выгоду это даст вам без лишнего контекста по этому вопросу.

Ответ 10

Вы можете попробовать расширить System.Collections.ObjectModel.Collection<T>, что намного более гибко. Затем вы можете переопределить защищенные члены InsertItem и SetItem, чтобы настроить поведение вашей коллекции.