Bir cevap daha ekleyelim. Neden bu diğerleri üzerinde?
1) Basitlik. Boyutu garanti etmeye çalışmak iyi ve iyidir, ancak kendi sorunlarını sergileyebilecek gereksiz karmaşıklığa yol açar.
2) IReadOnlyCollection'ı uygular, yani üzerinde Linq kullanabilir ve onu IEnumerable'ı bekleyen çeşitli şeylere aktarabilirsiniz.
3) Kilitleme yok. Yukarıdaki çözümlerin çoğu, kilitleri kullanır ve bu, kilitsiz bir koleksiyonda yanlıştır.
4) IProducerConsumerCollection da dahil olmak üzere ConcurrentQueue'nun yaptığı aynı yöntem, özellik ve arabirim kümesini uygular; bu, koleksiyonu BlockingCollection ile kullanmak istiyorsanız önemlidir.
TryDequeue başarısız olursa, bu uygulama potansiyel olarak beklenenden daha fazla girdiyle sonuçlanabilir, ancak bunun meydana gelme sıklığı, kaçınılmaz olarak performansı engelleyecek ve kendi beklenmedik sorunlarına neden olacak özel kodlara değmez.
Bir boyutu kesinlikle garanti etmek istiyorsanız, bir Prune () veya benzer bir yöntemi uygulamak en iyi fikir gibi görünüyor. Diğer yöntemlerde (TryDequeue dahil) ReaderWriterLockSlim okuma kilidi kullanabilir ve yalnızca budama sırasında bir yazma kilidi alabilirsiniz.
class ConcurrentFixedSizeQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>, ICollection {
readonly ConcurrentQueue<T> m_concurrentQueue;
readonly int m_maxSize;
public int Count => m_concurrentQueue.Count;
public bool IsEmpty => m_concurrentQueue.IsEmpty;
public ConcurrentFixedSizeQueue (int maxSize) : this(Array.Empty<T>(), maxSize) { }
public ConcurrentFixedSizeQueue (IEnumerable<T> initialCollection, int maxSize) {
if (initialCollection == null) {
throw new ArgumentNullException(nameof(initialCollection));
}
m_concurrentQueue = new ConcurrentQueue<T>(initialCollection);
m_maxSize = maxSize;
}
public void Enqueue (T item) {
m_concurrentQueue.Enqueue(item);
if (m_concurrentQueue.Count > m_maxSize) {
T result;
m_concurrentQueue.TryDequeue(out result);
}
}
public void TryPeek (out T result) => m_concurrentQueue.TryPeek(out result);
public bool TryDequeue (out T result) => m_concurrentQueue.TryDequeue(out result);
public void CopyTo (T[] array, int index) => m_concurrentQueue.CopyTo(array, index);
public T[] ToArray () => m_concurrentQueue.ToArray();
public IEnumerator<T> GetEnumerator () => m_concurrentQueue.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator();
// Explicit ICollection implementations.
void ICollection.CopyTo (Array array, int index) => ((ICollection)m_concurrentQueue).CopyTo(array, index);
object ICollection.SyncRoot => ((ICollection) m_concurrentQueue).SyncRoot;
bool ICollection.IsSynchronized => ((ICollection) m_concurrentQueue).IsSynchronized;
// Explicit IProducerConsumerCollection<T> implementations.
bool IProducerConsumerCollection<T>.TryAdd (T item) => ((IProducerConsumerCollection<T>) m_concurrentQueue).TryAdd(item);
bool IProducerConsumerCollection<T>.TryTake (out T item) => ((IProducerConsumerCollection<T>) m_concurrentQueue).TryTake(out item);
public override int GetHashCode () => m_concurrentQueue.GetHashCode();
public override bool Equals (object obj) => m_concurrentQueue.Equals(obj);
public override string ToString () => m_concurrentQueue.ToString();
}