Limiter la taille de la file d'attente <T> dans .NET?

voix
50

J'ai un objet de file d'attente <T> que j'initialisées à une capacité de 2, mais il est évident que la capacité est juste et que je continue son expansion ajouter des articles. Y at-il déjà un objet qui dequeues automatiquement un élément lorsque la limite est atteinte, ou est la meilleure solution pour créer ma propre classe héritée?

Créé 04/08/2008 à 15:47
source utilisateur
Dans d'autres langues...                            


7 réponses

voix
32

Je l'ai frappé une version de base de ce que je cherche, ce n'est pas parfait, mais ça va faire le travail jusqu'à ce que quelque chose de mieux se présente.

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);
    }
}
Créé 04/08/2008 à 15:57
source utilisateur

voix
17

Je recommande que vous tirez vers le haut de la bibliothèque C5 . Contrairement SCG (System.Collections.Generic), C5 est programmé à l' interface et conçu pour être sous - classé. La plupart des méthodes publiques sont virtuels et aucune des classes sont scellées. De cette façon, vous ne devez utiliser que Icky mot - clé « nouvelle » qui ne déclencherait pas si votre LimitedQueue<T>furent jetés à un SCG.Queue<T>. Avec C5 et en utilisant près du même code que vous aviez avant, vous tirer de la CircularQueue<T>. Le CircularQueue<T>met effectivement en œuvre à la fois une pile et une file d' attente, de sorte que vous pouvez obtenir les deux options avec une limite presque gratuitement. Je l' ai réécrit ci - dessous avec quelques constructions 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();
            }
        }
    }
}

Je pense que ce code devrait faire exactement ce que vous recherchez.

Créé 24/10/2008 à 14:51
source utilisateur

voix
5

Vous devez créer votre propre classe, un ringbuffer probablement répondre à vos besoins.

Les structures de données dans .NET qui vous permet de spécifier la capacité, à l'exception de tableau, utilise pour construire la structure interne de données utilisée pour contenir les données internes.

Par exemple, pour une liste, la capacité est utilisée à la taille d'un tableau interne. Lorsque vous commencez à ajouter des éléments à la liste, il va commencer à remplir ce tableau d'index 0 et, et quand il atteint votre capacité, il augmente la capacité d'une nouvelle capacité plus élevée, et continue à le remplir.

Créé 04/08/2008 à 15:56
source utilisateur

voix
3

Eh bien , j'espère que cette volonté de classe vous aide: En
interne , le FIFO mémoire tampon circulaire utilise une file d' attente <T> avec la taille spécifiée. Une fois la taille de la mémoire tampon est atteint, il remplace les articles plus anciens avec de nouveaux.

REMARQUE: Vous ne pouvez pas supprimer des éléments au hasard. Je mets la méthode Supprimer (point T) return false. si vous voulez vous pouvez modifier pour supprimer des éléments au hasard

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
}
Créé 15/11/2011 à 13:40
source utilisateur

voix
3

Pourquoi ne pas utiliser tout simplement un tableau avec une taille de 2? Une file d'attente est censé être en mesure de croître de façon dynamique et rétrécir.

Ou créer une classe wrapper autour d' une instance d' Queue<T>instance et chaque fois que l' on enqueues un <T>objet, vérifiez la taille de la file d' attente. Si plus de 2, dequeue le premier élément.

Créé 04/08/2008 à 15:52
source utilisateur

voix
1

Si elle est de toute utilisation à tout le monde, je fis 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; }
    }
}

Il supprime l'élément le plus ancien (en bas de la pile) quand il est trop grand.

(Cette question est le résultat Google top pour « la taille de C # pile limite »)

Créé 15/01/2012 à 06:28
source utilisateur

voix
0

Solution concurrente

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

Remarque: Comme Enqueuecontrôle l'ajout d'éléments, et le fait un à la fois, il n'y a pas besoin d'exécuter un whilepour TryDequeue.

Créé 09/05/2018 à 20:39
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more