Question

J'ai un objet Queue<T> que j'ai initialisé à une capacité de 2, mais évidemment ce n'est que la capacité et elle continue de s'étendre à mesure que j'ajoute des éléments.Existe-t-il déjà un objet qui retire automatiquement un élément de la file d'attente lorsque la limite est atteinte, ou la meilleure solution est-elle de créer ma propre classe héritée ?

Était-ce utile?

La solution

J'ai créé une version de base de ce que je recherche, elle n'est pas parfaite mais elle fera l'affaire jusqu'à ce que quelque chose de mieux arrive.

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

Autres conseils

Je vous recommanderais de remonter le Bibliothèque C5.Contrairement à SCG (System.Collections.Generic), C5 est programmé pour s'interfacer et conçu pour être sous-classé.La plupart des méthodes publiques sont virtuelles et aucune des classes n'est scellée.De cette façon, vous n'aurez pas besoin d'utiliser ce mot clé "nouveau" dégueulasse qui ne se déclencherait pas si votre LimitedQueue<T> ont été jetés à un SCG.Queue<T>.Avec C5 et en utilisant presque le même code qu'auparavant, vous dériveriez du CircularQueue<T>.Le CircularQueue<T> implémente en fait à la fois une pile et une file d'attente, vous pouvez donc 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 recherchiez.

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

Les structures de données dans .NET qui vous permettent de spécifier la capacité, à l'exception du tableau, l'utilisent pour créer la structure de données interne utilisée pour contenir les données internes.

Par exemple, pour une liste, la capacité est utilisée pour dimensionner un tableau interne.Lorsque vous commencez à ajouter des éléments à la liste, il commence à remplir ce tableau à partir de l'index 0 et lorsqu'il atteint votre capacité, il augmente la capacité jusqu'à une nouvelle capacité supérieure et continue de le remplir.

Pourquoi n'utiliseriez-vous pas simplement un tableau d'une taille de 2 ?Une file d'attente est censée pouvoir croître et diminuer de manière dynamique.

Ou créez une classe wrapper autour d'une instance de Queue<T> instance et chaque fois que l'on met en file d'attente un <T> objet, vérifiez la taille de la file d’attente.S'il est supérieur à 2, retirez le premier élément de la file d'attente.

Eh bien, j'espère que ce cours vous aidera :
En interne, le tampon FIFO circulaire utilise un Queue<T> avec la taille spécifiée.Une fois la taille du tampon atteinte, il remplacera les anciens éléments par de nouveaux.

NOTE:Vous ne pouvez pas supprimer des éléments au hasard.J'ai défini la méthode Remove(T item) pour qu'elle renvoie false.si vous le souhaitez, vous pouvez modifier pour supprimer des éléments de manière aléatoire

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
}

Si ça peut servir à quelqu'un, j'ai fait un 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) lorsqu'il devient trop gros.

(Cette question était le meilleur résultat Google pour "Taille limite de la pile C#")

Solution simultanée

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

Note:Depuis Enqueue contrôle l'ajout d'éléments, et ce un à la fois, il n'est pas nécessaire d'exécuter un while pour TryDequeue.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top