web-dev-qa-db-fra.com

Comment remplacer la méthode Add de la liste <T> en C #?

Je cherche actuellement à créer ma propre collection, qui ressemblerait à une liste normale, à la différence près qu'elle ne contiendrait que 10 articles. Si un élément était ajouté alors qu'il y avait déjà 10 éléments dans la liste, le premier élément serait supprimé avant l'ajout du nouvel élément.

Ce que je veux faire, c'est créer une classe qui étend System.Collections.Generic.List<T>, puis modifie la méthode Add(T item) pour inclure la fonctionnalité qui supprime le premier élément si nécessaire.

33
shinyhappydan

Tout d'abord, vous ne pouvez pas remplacer Add et conservez le polymorphisme contre List , ce qui signifie que si vous utilisez le nouveau mot-clé et que votre classe est convertie en List, votre nouvelle méthode Add ne sera pas appelée.

Deuxièmement, je vous suggère de regarder dans Queue class, car ce que vous essayez de faire est plus une file d’attente qu’une liste. La classe est optimisée pour exactement ce que vous voulez faire, mais n’a pas de limiteur de taille. 

Si vous voulez vraiment que quelque chose agisse comme une liste mais fonctionne comme une file d'attente avec une taille maximale, je vous suggère d'implémenter IList et de conserver une instance d'une file d'attente pour stocker vos éléments. 

Par exemple:

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
}
41
Randolpho

Vous pouvez également implémenter la méthode add via

public new void Add(...)

dans votre classe dérivée pour masquer l’ajout existant et introduire votre fonctionnalité.

Modifier: Contours approximatifs ...

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

        base.Add(item);
    }
}

Juste une note, supposée implicite, mais vous devez toujours référencer votre liste personnalisée par le type réel et jamais par le type/interface de base car la méthode de masquage n'est disponible que pour votre type et les types dérivés ultérieurs.

65
Quintin Robinson

Vous ne pouvez pas remplacer Add (), ce n'est pas une méthode virtuelle. Dérivez d'IList et utilisez un membre de file d'attente privé pour l'implémentation.

26
Hans Passant

Vous pouvez étendre System.Collections.ObjectModel.Collection et substituer la méthode InsertItem pour obtenir le comportement souhaité, et elle implémente également IList.

17
Lee

Vous pouvez simplement écrire une classe qui implémente IList<T> qui contient un List<T> interne et écrire vos propres méthodes.

8
Ryan Emerle

Il semble que le mieux que je puisse faire est la suivante:

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);
        }
}

Puisque la méthode add() n'est pas marquée comme virtuelle.

5
shinyhappydan

Votre description de votre besoin sonne comme un Tampon circulaire .

J'ai implémenté mon propre - semblable à cette implémentation sur CodePlex sauf que le mien implémente IList<T>.

Certaines des autres réponses suggèrent d'utiliser un Queue<T> - mais ce n'est pas tout à fait la même chose, car cela permet uniquement l'accès FIFO.

En règle générale, il n'est pas recommandé de dériver de List<T>, mais plutôt de Collection<T> et d'implémenter tout élément supplémentaire dont vous avez besoin. Mais pour un tampon circulaire, il est probablement plus approprié d'utiliser un tableau privé plutôt que de dériver de Collection<T> comme l'implémentation de CodePlex.

3
Joe

Lisez le principe de Principe de substitution de Liskov , votre collection est un très mauvais candidat pour étendre List<T>, ce n’est même pas un très bon candidat pour implémenter IList<T>.

Quels sont les modèles de lecture requis sur ces données? Si vous devez uniquement examiner toutes les entrées actuelles, la mise en œuvre de IEnumerable<T> et de la méthode Add (T) devrait suffire.

Ceci peut alors être implémenté par une file privée (ou Deque serait mieux, mais une telle collection nécessiterait une autre API de collections et je ne vous suggère pas d'essayer d'en implémenter une) à laquelle vous Enqueue () lors d'une Add nécessaire pour maintenir la taille).

Notez que l'implémentation de IEnumerable et la fourniture de la méthode Add signifient que vous pouvez toujours utiliser la syntaxe d'initialisation de Collection si nécessaire. 

Si vous avez besoin d'un accès aléatoire aux valeurs, alors implémenter un indexeur peut être une bonne idée, mais je ne vois pas quel avantage cela vous donnerait sans plus de contexte sur la question.

1
ShuggyCoUk

Vous pouvez jeter un oeil à la bibliothèque de collections C5. Ils ont un ArrayList <T> qui implémente IList <T> et ont une méthode virtuelle Add. La bibliothèque de collections C5 est une collection impressionnante de listes, files d'attente, piles, etc. Vous pouvez trouver la bibliothèque C5 ici:

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

1
JohannesH

Vous pouvez essayer d’étendre System.Collections.ObjectModel.Collection<T>, ce qui est beaucoup plus flexible. Vous pouvez ensuite remplacer les membres protégés InsertItem et SetItem pour personnaliser le comportement de votre collection.

0
bastio84