如何在 C# 中覆盖 List<T> 的 Add 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/580202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I override List<T>'s Add method in C#?
提问by shinyhappydan
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.
我目前正在寻找制作我自己的收藏,这就像一个常规列表,只是它只能容纳 10 个项目。如果在列表中已经有 10 个项目时添加了一个项目,那么第一个项目将在附加新项目之前被删除。
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.
我想要做的是创建一个扩展类,System.Collections.Generic.List<T>
然后修改该Add(T item)
方法以包含必要时删除第一项的功能。
采纳答案by Randolpho
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.
首先,您不能覆盖 Add 并且仍然具有针对List 的多态性,这意味着如果您使用 new 关键字并且您的类被强制转换为 List ,则不会调用您的新 Add 方法。
Second, I suggest you look into the Queueclass, 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.
其次,我建议您查看Queue类,因为您要做的更像是一个队列而不是一个列表。该类针对您想要做的事情进行了优化,但没有任何大小限制器。
If you really want something to act like a List but work like a Queue with a maximum size, I suggest you implement IListand keep an instance of a Queue to store your elements.
如果你真的想要一些像 List 一样的东西,但像一个最大大小的 Queue 一样工作,我建议你实现IList并保留一个 Queue 的实例来存储你的元素。
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
}
回答by Hans Passant
You can't override Add(), it is not a virtual method. Derive from IList instead and use a private Queue member for the implementation.
您不能覆盖 Add(),它不是虚拟方法。而是从 IList 派生并使用私有队列成员进行实现。
回答by Ryan Emerle
You can just write a class that implements IList<T>
that holds an internal List<T>
and write your own methods.
您可以只编写一个实现IList<T>
内部的类List<T>
并编写自己的方法。
回答by Quintin Robinson
You can also implement the add method via
您还可以通过实现 add 方法
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.
只是一个说明,认为它是隐含的,但您必须始终通过实际类型而不是基类型/接口引用您的自定义列表,因为隐藏方法仅适用于您的类型和进一步派生的类型。
回答by shinyhappydan
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.
由于该add()
方法未标记为虚拟。
回答by JohannesH
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:
您可以查看 C5 集合库。他们有一个实现 IList<T> 的 ArrayList<T> 并有一个虚拟的 Add 方法。C5 集合库是一个很棒的列表、队列、堆栈等集合......你可以在这里找到 C5 库:
回答by ShuggyCoUk
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>
.
阅读Liskov 替换原则,您的集合是扩展 List 的一个非常糟糕的候选者<T>
,它甚至不是实现 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.
这些数据需要什么样的读取模式?如果您只需要查看所有当前条目,那么开始实现 IEnumerable<T>
和 Add(T) 方法就足够了。
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).
然后这可以通过私有队列实现(或者 Deque 会更好,但这样的集合需要一些其他集合 API,我不建议您尝试自己实现一个)您在添加期间 Enqueue() 到其中(使用 Dequeue 的 if需要保持大小)。
Note that implementing IEnumerable and providing the Add method means you can still use the Collection initialiser syntax if required.
请注意,实现 IEnumerable 并提供 Add 方法意味着如果需要,您仍然可以使用集合初始化程序语法。
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.
如果您需要随机访问这些值,那么实现索引器可能是一个好主意,但如果没有更多关于该问题的上下文,我看不出这会给您带来什么好处。
回答by Lee
You could extend System.Collections.ObjectModel.Collectionand override the InsertItem method to get the behaviour you want, and it also implements IList
您可以扩展System.Collections.ObjectModel.Collection并覆盖 InsertItem 方法以获得所需的行为,并且它还实现了 IList
回答by Joe
Your description of your requirement sounds like a Circular Buffer.
您对需求的描述听起来像一个Circular Buffer。
I implemented my own - similar to this implementation on CodePlexexcept that mine implements IList<T>
.
我实现了我自己的 - 类似于CodePlex上的这个实现,除了我的实现IList<T>
.
Some of the other answers suggest using a Queue<T>
- but this isn't quite the same thing, as it only allows FIFO access.
其他一些答案建议使用Queue<T>
- 但这并不完全相同,因为它只允许 FIFO 访问。
As a general point, it's not recommended to derive from List<T>
- instead derive from Collection<T>
, and implement any additional stuff you need. But for a circular buffer it's probably more appropriate to use a private array rather than deriving from Collection<T>
like the CodePlex implementation.
一般来说,不建议派生自List<T>
- 而是派生自Collection<T>
,并实现您需要的任何其他内容。但是对于循环缓冲区,使用私有数组而不是Collection<T>
像 CodePlex 实现那样派生可能更合适。
回答by bastio84
You can try to extend System.Collections.ObjectModel.Collection<T>
, which is much more flexible. You can then override the protected members InsertItem
and SetItem
, to customize the behaviour of your collection.
您可以尝试扩展System.Collections.ObjectModel.Collection<T>
,这更加灵活。然后,您可以覆盖受保护的成员InsertItem
和SetItem
, 以自定义集合的行为。