.NET是否内置可访问最近n个元素的固定长度循环列表?
.NET中维护固定大小的最近元素列表方案
核心结论
目前.NET官方类库没有直接内置这种“固定大小、自动保留最近n个元素、支持访问全部保留元素”的开箱即用结构。
为什么Queue不满足需求
Queue是FIFO结构,虽然可以通过手动限制元素数量实现淘汰旧元素,但它的设计目标是便捷存取首尾元素:
- 无法直接通过索引访问中间元素,要访问全部元素只能遍历,不符合“随时直观访问全部元素”的需求;
- 遍历操作可行,但使用体验和效率都不如专门设计的结构。
推荐实现方案
1. 基于List的简单封装(适合大多数场景)
这种实现代码简洁、易于理解,适合元素数量不大、添加频率不高的场景:
public class FixedSizeList<T> { private readonly List<T> _innerList = new List<T>(); private readonly int _maxCapacity; public FixedSizeList(int maxCapacity) { _maxCapacity = maxCapacity > 0 ? maxCapacity : throw new ArgumentOutOfRangeException(nameof(maxCapacity)); } public void Add(T item) { _innerList.Add(item); if (_innerList.Count > _maxCapacity) { _innerList.RemoveAt(0); } } // 支持索引访问指定元素 public T this[int index] => _innerList[index]; public int Count => _innerList.Count; // 返回只读集合,避免外部修改内部列表 public IReadOnlyList<T> Items => _innerList.AsReadOnly(); }
注意:当元素数量超过_maxCapacity时,RemoveAt(0)是O(n)操作,若n很大且高频添加,会存在性能损耗。
2. 环形数组实现(高性能场景)
如果需要高频添加元素,环形数组实现可以做到O(1)复杂度的添加操作,同时支持索引访问和遍历:
public class CircularBuffer<T> { private readonly T[] _buffer; private int _headIndex; private int _tailIndex; private int _currentCount; public CircularBuffer(int capacity) { if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity)); _buffer = new T[capacity]; } public void Add(T item) { _buffer[_tailIndex] = item; _tailIndex = (_tailIndex + 1) % _buffer.Length; if (_currentCount < _buffer.Length) { _currentCount++; } else { _headIndex = (_headIndex + 1) % _buffer.Length; } } // 按添加顺序索引访问元素 public T this[int index] { get { if (index < 0 || index >= _currentCount) throw new IndexOutOfRangeException(); return _buffer[(_headIndex + index) % _buffer.Length]; } } public int Count => _currentCount; public int Capacity => _buffer.Length; // 遍历所有保留的元素(按添加顺序输出) public IEnumerable<T> GetOrderedItems() { for (int i = 0; i < _currentCount; i++) { yield return this[i]; } } }
内容的提问来源于stack exchange,提问作者ispiro
相关产品推荐
相关产品推荐

