2008-08-04 17 views
49

2 tane kapasiteye başlamış olduğum bir Queue <T> nesnesine sahibim, ancak açıkçası bu sadece kapasite ve ekledikçe öğeler eklediğimde devam ediyor. Limite ulaşıldığında bir öğeyi otomatik olarak deşifre eden bir nesne mi yoksa kendi miras alınan sınıfımı oluşturmak için en iyi çözüm var mı?. NET'te Kuyruk <T> Sınır boyutu?

cevap

31

Aradığım şeyin temel bir sürümünü çaldım, bu mükemmel değil ama daha iyi bir şey gelene kadar işi yapacak.

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); 
    } 
} 
+0

(Bu soru "C# sınırı yığın boyutu" için en iyi Google sonucuydu) Limit - sadece basit bir Limit, Dequeue daha büyük iken. Bunun dışında, bu harika ve basit bir çözüm, teşekkürler. – Scott

+0

'Limit' özelliği için 'ayarlayıcı' kodunu değiştirmede iyi yol. –

+17

Marcus Griep onun cevabını ima bu sınıfın, çok ciddi bir sınırlama vardır: ('Sıra .Enqueue' sanal olmadığı için) sizin' Enqueue' yöntemi new' 'olarak ilan edildiğinden, birileri' LimitedQueue atmalarını eğer ',' Queue 'ile limit alma etkisi olmadan istedikleri kadar öğe ekleyebilecekler. Ben de (örneğin, (this.Count> = this.Limit) 'ifadesini '' (this.Count> = this.Limit)' olarak değiştirmeyi tavsiye ederim, sadece güvenli tarafta olmak (örneğin bahsettiğim senaryo için)). –

3

Neden 2 boyutunda bir dizi kullanmıyorsunuz? Bir Kuyruğun dinamik olarak büyümesi ve küçültülmesi gerekiyordu. Veya Queue<T> örneğinin bir örneğinin etrafına bir sarıcı sınıfı oluşturun ve her defasında bir <T> nesnesini işaretlediğinde, kuyruğun boyutunu kontrol edin.'den büyükse, ilk öğeyi dequeue.

5

Kendi sınıfınızı oluşturmalısınız, zil sesi muhtemelen ihtiyaçlarınızı karşılayacaktır.

.NET dışındaki veri yapıları, dizi dışında kapasite belirlemenize olanak tanır, iç verileri tutmak için kullanılan iç veri yapısını oluşturmak için bunu kullanır. Örneğin, bir liste için bir iç diziyi boyutlandırmak için kapasite kullanılır. Listeye öğeler eklemeye başladığınızda, bu diziyi 0 ve üstü doldurmaya başlar ve kapasitenize ulaştığında, kapasiteyi daha yüksek bir kapasiteye çıkarır ve doldurmaya devam eder.

15

C5 Library'u yukarı çekmenizi tavsiye ederim. SCG'den (System.Collections.Generic) farklı olarak C5, arayüzlenecek ve alt sınıflanacak şekilde programlanır. Çoğu genel yöntem sanaltır ve sınıfların hiçbiri mühürlenmez. Bu şekilde, LimitedQueue<T> ürününüzün SCG.Queue<T> ürününe aktarılması durumunda tetiklemeyecek olan bu "yeni" anahtar kelimeyi kullanmanız gerekmeyecektir. C5 ile ve daha önce sahip olduğunuzla aynı kodu kullanarak, CircularQueue<T>'dan türetilirsiniz. CircularQueue<T> aslında hem yığın hem de kuyruk uygular, böylece her iki seçeneği de neredeyse ücretsiz olan bir sınırla alabilirsiniz. Bazı 3,5 yapıları ile altına yeniden kaleme aldık:

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(); 
      } 
     } 
    } 
} 

Bu kod aradığınız tam olarak ne yapması gerektiğini düşünüyorum.

3

Eh ben bu sınıf irade You yardımcı olur umarım:
Dahili Dairesel FIFO Tampon belirtilen boyutta bir Kuyruk <T> kullanın. Arabellek boyutuna ulaşıldığında, eski öğeleri yenileriyle değiştirir.

NOT: Öğeleri rastgele kaldıramazsınız. False değerini döndürmek için Remove (T item) yöntemini ayarlıyorum. Sen istersen o kimseye herhangi bir kullanım varsa rastgele

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 
} 
+1

neden olabilir ben de Dairesel tampon Sınırlı bir boyut queue..which olabilir bu kodu kullanarak düşünüyorum. –

1

öğeleri kaldırmak için değiştirebilirsiniz, ben LimitedStack<T> yaptı.

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; } 
    } 
} 

Çok büyük olduğunda, en eski öğeyi (yığınının altını) çıkarır.

Ben Kuyruk boyutu aşıp aşmadığını sağlayan Sınır özelliğinin Set içinden bir çağrı ile hafifçe kod artar

+0

Bu kod 99% doğrudur. Bununla birlikte, Peek veya Pop'u yığına herhangi bir şey koymadan çağırırsak, indeks -1 olarak çökecektir. Bu, dizin sınırları denetimi ekleyerek kolayca düzeltilebilir. – Contango

+0

Peek için aşağıdaki ve ekleme Gösteriyor Pop(): \t \t \t if ((_stack.Count - 1) <0) ("Peek ya da ilk bir itin yapmadan Pop Can not") throw new Exception ;. Bu, programcıyı bu köşe kasasına uyarır ve bu sınıfı kullanırken akılda tutmasına izin verir. Ayrıca Microsoft'un ConcurrentDictionary uygulamalarıyla çektiği yaklaşım olan bir TryPeek veya TryPop ekleyebiliriz. – Contango

+1

Kayıt için, bu kod ek kilitleme olmadan vida dişi değildir (bu kesinlikle hassastır, iplik güvenliği bu sınıfın tasarım özelliklerinin hiçbir zaman bir parçası değildir). – Contango