Как мне переопределить метод Add в List ‹T› в C #?

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

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


person shinyhappydan    schedule 24.02.2009    source источник


Ответы (10)


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

Во-вторых, я предлагаю вам изучить класс 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
}
person Randolpho    schedule 24.02.2009
comment
Я согласен, я думаю, что очередь - лучший вариант в этом сценарии. - person Quintin Robinson; 24.02.2009
comment
Имейте в виду, что предлагаемый мной код никоим образом не является потокобезопасным. Вам придется сделать это самому. :) - person Randolpho; 24.02.2009
comment
@ Квентин: Действительно, я согласен, сэр. - person Randolpho; 24.02.2009
comment
точно так же, как обычный список, за исключением того, что он будет содержать только 10 элементов, для меня это больше похоже на круговой буфер, чем на очередь. Смотрите мой ответ. - person Joe; 09.04.2011

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

public new void Add(...)

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

Изменить: грубый контур ...

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

        base.Add(item);
    }
}

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

person Quintin Robinson    schedule 24.02.2009
comment
По-видимому, я проголосовал против этого, когда хотел проголосовать за, но, осознав это сейчас, я не могу это изменить :( - person Derek Beattie; 01.05.2018

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

person Hans Passant    schedule 24.02.2009

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

person Lee    schedule 24.02.2009

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

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

person shinyhappydan    schedule 24.02.2009
comment
Это очень плохая идея, ваш класс больше не ведет себя правильно в зависимости от типа переменной, используемой для отправки сообщения Добавить. На самом деле вам нужно прочитать LSP и описываемую в нем заменяемость. - person ShuggyCoUk; 24.02.2009
comment
Имейте в виду, что если вы используете этот метод, ваш класс не будет работать, если он приведен как список. Ваш новый метод Add никогда не будет вызван. Вам действительно стоит подумать об использовании очереди. - person Randolpho; 24.02.2009
comment
@ShuggyCoUk что означает LSP? - person UpTide; 19.04.2018

Описание вашего требования похоже на круговой буфер.

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

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

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

person Joe    schedule 09.04.2011
comment
Коллекция также не позволяет мне переопределить Добавить. - person Rafe; 13.03.2014

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

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

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

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

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

person ShuggyCoUk    schedule 24.02.2009

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

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

person JohannesH    schedule 24.02.2009

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

person bastio84    schedule 19.03.2016