Hãy thêm một câu trả lời nữa. Tại sao điều này hơn những người khác?
1) Tính đơn giản. Cố gắng đảm bảo kích thước là tốt và tốt nhưng dẫn đến sự phức tạp không cần thiết có thể bộc lộ các vấn đề riêng của nó.
2) Triển khai IReadOnlyCollection, nghĩa là bạn có thể sử dụng Linq trên đó và chuyển nó vào nhiều thứ khác nhau mà IEnumerable mong đợi.
3) Không khóa. Nhiều giải pháp ở trên sử dụng khóa, điều này không chính xác đối với bộ sưu tập không khóa.
4) Triển khai cùng một tập hợp các phương thức, thuộc tính và giao diện mà ConcurrentQueue thực hiện, bao gồm cả IProductionerConsumerCollection, điều này rất quan trọng nếu bạn muốn sử dụng bộ sưu tập với BlockingCollection.
Việc triển khai này có khả năng kết thúc với nhiều mục nhập hơn dự kiến nếu TryDequeue không thành công, nhưng tần suất xuất hiện của điều đó dường như không đáng giá đối với mã chuyên dụng, chắc chắn sẽ cản trở hiệu suất và gây ra các vấn đề không mong muốn của chính nó.
Nếu bạn hoàn toàn muốn đảm bảo kích thước, việc triển khai Prune () hoặc phương thức tương tự có vẻ là ý tưởng tốt nhất. Bạn có thể sử dụng khóa đọc ReaderWriterLockSlim trong các phương pháp khác (bao gồm cả TryDequeue) và chỉ thực hiện khóa ghi khi lược bỏ.
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();
}