我有一个队列< T>我初始化为2的容量的对象,但显然这只是容量,并且随着我添加项目而不断扩展。是否已有一个对象在达到限制时自动使项目出列,或者是创建自己的继承类的最佳解决方案?
答案 0 :(得分:35)
我已经找到了我正在寻找的基本版本,但这并不完美,但它会完成工作,直到有更好的东西出现。
public class LimitedQueue<T> : Queue<T>
{
public int Limit { get; set; }
public LimitedQueue(int limit) : base(limit)
{
Limit = limit;
}
public new void Enqueue(T item)
{
while (Count >= Limit)
{
Dequeue();
}
base.Enqueue(item);
}
}
答案 1 :(得分:17)
我建议你拉出C5 Library。与SCG(System.Collections.Generic)不同,C5被编程为接口并设计为子类。大多数公共方法都是虚拟的,没有一个类是密封的。这样,您就不必使用那个icky“new”关键字,如果LimitedQueue<T>
被投放到SCG.Queue<T>
,则不会触发该关键字。使用C5并使用与之前相同的代码,您可以从CircularQueue<T>
派生。 CircularQueue<T>
实际上实现了堆栈和队列,因此您可以获得具有几乎免费限制的两个选项。我在下面用3.5个构造重写了它:
using C5;
public class LimitedQueue<T> : CircularQueue<T>
{
public int Limit { get; set; }
public LimitedQueue(int limit) : base(limit)
{
this.Limit = limit;
}
public override void Push(T item)
{
CheckLimit(false);
base.Push(item);
}
public override void Enqueue(T item)
{
CheckLimit(true);
base.Enqueue(item);
}
protected virtual void CheckLimit(bool enqueue)
{
while (this.Count >= this.Limit)
{
if (enqueue)
{
this.Dequeue();
}
else
{
this.Pop();
}
}
}
}
我认为这段代码应该完全符合您的要求。
答案 2 :(得分:5)
你应该创建自己的类,一个ringbuffer可能符合你的需要。
.NET中允许您指定容量的数据结构(数组除外)使用它来构建用于保存内部数据的内部数据结构。
例如,对于列表,容量用于调整内部数组的大小。当您开始向列表中添加元素时,它将从索引0开始向上填充此数组,当它达到您的容量时,它会将容量增加到更高的容量,并继续填充它。
答案 3 :(得分:3)
为什么不使用大小为2的数组?队列应该能够动态增长和缩小。
或者围绕Queue<T>
实例的实例创建一个包装类,每次将一个<T>
对象排入队列,检查队列的大小。如果大于2,则将第一个项目出列。
答案 4 :(得分:3)
我希望这堂课会帮助你:
在内部,循环FIFO缓冲器使用队列&lt; T&gt;。具有指定的大小。
一旦达到缓冲区的大小,它将用新的项目替换旧项目。
注意:您无法随机删除项目。我设置方法Remove(T item)返回false。 如果您需要您可以修改以随机删除项目
public class CircularFIFO<T> : ICollection<T> , IDisposable
{
public Queue<T> CircularBuffer;
/// <summary>
/// The default initial capacity.
/// </summary>
private int capacity = 32;
/// <summary>
/// Gets the actual capacity of the FIFO.
/// </summary>
public int Capacity
{
get { return capacity; }
}
/// <summary>
/// Initialize a new instance of FIFO class that is empty and has the default initial capacity.
/// </summary>
public CircularFIFO()
{
CircularBuffer = new Queue<T>();
}
/// <summary>
/// Initialize a new instance of FIFO class that is empty and has the specified initial capacity.
/// </summary>
/// <param name="size"> Initial capacity of the FIFO. </param>
public CircularFIFO(int size)
{
capacity = size;
CircularBuffer = new Queue<T>(capacity);
}
/// <summary>
/// Adds an item to the end of the FIFO.
/// </summary>
/// <param name="item"> The item to add to the end of the FIFO. </param>
public void Add(T item)
{
if (this.Count >= this.Capacity)
Remove();
CircularBuffer.Enqueue(item);
}
/// <summary>
/// Adds array of items to the end of the FIFO.
/// </summary>
/// <param name="item"> The array of items to add to the end of the FIFO. </param>
public void Add(T[] item)
{
int enqueuedSize = 0;
int remainEnqueueSize = this.Capacity - this.Count;
for (; (enqueuedSize < item.Length && enqueuedSize < remainEnqueueSize); enqueuedSize++)
CircularBuffer.Enqueue(item[enqueuedSize]);
if ((item.Length - enqueuedSize) != 0)
{
Remove((item.Length - enqueuedSize));//remaining item size
for (; enqueuedSize < item.Length; enqueuedSize++)
CircularBuffer.Enqueue(item[enqueuedSize]);
}
}
/// <summary>
/// Removes and Returns an item from the FIFO.
/// </summary>
/// <returns> Item removed. </returns>
public T Remove()
{
T removedItem = CircularBuffer.Peek();
CircularBuffer.Dequeue();
return removedItem;
}
/// <summary>
/// Removes and Returns the array of items form the FIFO.
/// </summary>
/// <param name="size"> The size of item to be removed from the FIFO. </param>
/// <returns> Removed array of items </returns>
public T[] Remove(int size)
{
if (size > CircularBuffer.Count)
size = CircularBuffer.Count;
T[] removedItems = new T[size];
for (int i = 0; i < size; i++)
{
removedItems[i] = CircularBuffer.Peek();
CircularBuffer.Dequeue();
}
return removedItems;
}
/// <summary>
/// Returns the item at the beginning of the FIFO with out removing it.
/// </summary>
/// <returns> Item Peeked. </returns>
public T Peek()
{
return CircularBuffer.Peek();
}
/// <summary>
/// Returns the array of item at the beginning of the FIFO with out removing it.
/// </summary>
/// <param name="size"> The size of the array items. </param>
/// <returns> Array of peeked items. </returns>
public T[] Peek(int size)
{
T[] arrayItems = new T[CircularBuffer.Count];
CircularBuffer.CopyTo(arrayItems, 0);
if (size > CircularBuffer.Count)
size = CircularBuffer.Count;
T[] peekedItems = new T[size];
Array.Copy(arrayItems, 0, peekedItems, 0, size);
return peekedItems;
}
/// <summary>
/// Gets the actual number of items presented in the FIFO.
/// </summary>
public int Count
{
get
{
return CircularBuffer.Count;
}
}
/// <summary>
/// Removes all the contents of the FIFO.
/// </summary>
public void Clear()
{
CircularBuffer.Clear();
}
/// <summary>
/// Resets and Initialize the instance of FIFO class that is empty and has the default initial capacity.
/// </summary>
public void Reset()
{
Dispose();
CircularBuffer = new Queue<T>(capacity);
}
#region ICollection<T> Members
/// <summary>
/// Determines whether an element is in the FIFO.
/// </summary>
/// <param name="item"> The item to locate in the FIFO. </param>
/// <returns></returns>
public bool Contains(T item)
{
return CircularBuffer.Contains(item);
}
/// <summary>
/// Copies the FIFO elements to an existing one-dimensional array.
/// </summary>
/// <param name="array"> The one-dimensional array that have at list a size of the FIFO </param>
/// <param name="arrayIndex"></param>
public void CopyTo(T[] array, int arrayIndex)
{
if (array.Length >= CircularBuffer.Count)
CircularBuffer.CopyTo(array, 0);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return false;
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return CircularBuffer.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return CircularBuffer.GetEnumerator();
}
#endregion
#region IDisposable Members
/// <summary>
/// Releases all the resource used by the FIFO.
/// </summary>
public void Dispose()
{
CircularBuffer.Clear();
CircularBuffer = null;
GC.Collect();
}
#endregion
}
答案 5 :(得分:1)
如果对任何人有用,我都会LimitedStack<T>
。
public class LimitedStack<T>
{
public readonly int Limit;
private readonly List<T> _stack;
public LimitedStack(int limit = 32)
{
Limit = limit;
_stack = new List<T>(limit);
}
public void Push(T item)
{
if (_stack.Count == Limit) _stack.RemoveAt(0);
_stack.Add(item);
}
public T Peek()
{
return _stack[_stack.Count - 1];
}
public void Pop()
{
_stack.RemoveAt(_stack.Count - 1);
}
public int Count
{
get { return _stack.Count; }
}
}
当它变得太大时,它会删除最旧的项目(堆栈的底部)。
(这个问题是#34的最高结果; C#限制堆栈大小&#34;)
答案 6 :(得分:1)
public class LimitedConcurrentQueue<ELEMENT> : ConcurrentQueue<ELEMENT>
{
public readonly int Limit;
public LimitedConcurrentQueue(int limit)
{
Limit = limit;
}
public new void Enqueue(ELEMENT element)
{
base.Enqueue(element);
if (Count > Limit)
{
TryDequeue(out ELEMENT discard);
}
}
}
注意:由于Enqueue
控制元素的添加,并且一次只执行一个,因此无需为while
执行TryDequeue
。
答案 7 :(得分:1)
您可以使用LinkedList<T>
并添加线程安全性:
public class Buffer<T> : LinkedList<T>
{
private int capacity;
public Buffer(int capacity)
{
this.capacity = capacity;
}
public void Enqueue(T item)
{
// todo: add synchronization mechanism
if (Count == capacity) RemoveLast();
AddFirst(item);
}
public T Dequeue()
{
// todo: add synchronization mechanism
var last = Last.Value;
RemoveLast();
return last;
}
}
要注意的是默认的枚举顺序在此示例中为LIFO。但这可以在必要时被覆盖。