views:

5217

answers:

8

I am currently looking to make my own collection, which would be just like a regular list, except that it would only hold 10 items. If an item was added when there were already 10 items in the list, then the first item would be removed before the new item was appended.

What I want to do is create a class that extends System.Collections.Generic.List<T>, and then modifies the Add(T item) method to include the functionality which removes the first item if necessary.

+17  A: 

You can't override Add(), it is not a virtual method. Derive from IList instead and use a private Queue member for the implementation.

Hans Passant
+3  A: 

You can just write a class that implements IList<T> that holds an internal List<T> and write your own methods.

Ryan Emerle
+12  A: 

You can also implement the add method via

public new void Add(...)

in your derived class to hide the existing add and introduce your functionality.

Edit: Rough Outline...

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

     base.Add(item);
    }
}

Just a note, figured it was implied but you must always reference your custom list by the actual type and never by the base type/interface as the hiding method is only available to your type and further derived types.

Quintin Robinson
+1 for easy to understand answer.
Jamie Keeling
+4  A: 

It seems like the best I can do is this:

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

Since the add() method is not marked as virtual.

shinyhappydan
This is a very bad idea, your class no longer behaves correctly depending on the type of the variable used to send the Add message. *Really* you need to read up on LSP and the substitutability it describes
ShuggyCoUk
Keep in mind that if you use this method, your class will not work if it is cast as a List. Your new Add method will never get called. You really should consider using a queue.
Randolpho
+13  A: 

First, you can't override Add and still have polymorphism against List, meaning that if you use the new keyword and your class is cast as a List, your new Add method won't be called.

Second, I suggest you look into the Queue class, as what you are trying to do is more of a queue than it is a list. The class is optimized for exactly what you want to do, but does not have any sort of a size limiter.

If you really want something to act like a List but work like a Queue with a maximum size, I suggest you implement IList and keep an instance of a Queue to store your elements.

For example:

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
}
Randolpho
I agree, I think a queue is the best option in this scenario.
Quintin Robinson
Keep in mind that my suggested code is in no way threadsafe. You'll have to do that yourself. :)
Randolpho
@Quentin: Indeed, I agree, sir.
Randolpho
Excellent answer, thanks.
DMan
+1  A: 

You could take a look at the C5 collection library. They have an ArrayList<T> that implements IList<T> and have a virtual Add method. The C5 collection library is an awesome collection of lists, queues, stacks etc... You can find the C5 library here:

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

JohannesH
+1  A: 

Have a read of the Liskov Substitution Principle, your collection is a very poor candidate to extend List<T>, it is not even a great candidate to implement IList<T>.

What read patterns are required on this data? If you only need to look at all the current entries then implementing IEnumerable<T> and the Add(T) method should be sufficient to start with.

This can then be implemented by a private Queue (or Deque would be better but such a collection would require some other collections API and I do not suggest you try to implement one yourself) to which you Enqueue() during an Add (with Dequeue's if needed to maintain the size).

Note that implementing IEnumerable and providing the Add method means you can still use the Collection initialiser syntax if required.

If you need random access to the values then implementing an indexer may be a good idea but I don't see what benefit this would give you without more context on the question.

ShuggyCoUk
+3  A: 

You could extend System.Collections.ObjectModel.Collection and override the InsertItem method to get the behaviour you want, and it also implements IList

Lee
+1 deriving from List<T> is wrong.
Dog Ears