Как переопределить метод Add List <T>в C #? - PullRequest
34 голосов
/ 24 февраля 2009

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

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

Ответы [ 10 ]

65 голосов
/ 24 февраля 2009

Вы также можете реализовать метод добавления через

public new void Add(...)

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

Редактировать: Грубый контур ...

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

        base.Add(item);
    }
}

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

43 голосов
/ 24 февраля 2009

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

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

Если вы действительно хотите, чтобы что-то действовало как список, но работал как очередь с максимальным размером, я предлагаю вам реализовать 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
}
26 голосов
/ 24 февраля 2009

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

17 голосов
/ 24 февраля 2009

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

8 голосов
/ 24 февраля 2009

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

5 голосов
/ 24 февраля 2009

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

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

3 голосов
/ 09 апреля 2011

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

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

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

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

1 голос
/ 24 февраля 2009

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

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

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

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

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

1 голос
/ 24 февраля 2009

Вы можете взглянуть на библиотеку коллекции C5. Они имеют ArrayList , который реализует IList , и имеют виртуальный метод Add. Библиотека коллекции C5 - это удивительная коллекция списков, очередей, стеков и т. Д. Библиотека C5 находится здесь:

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

0 голосов
/ 19 марта 2016

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

...