Search This Blog

Thursday, April 17, 2014

C#.Net Time delayed queue of T.

Please note that the T object must implement IEquatable!!


/// <summary>
/// Time Delay Queue.
/// Generic object must implement IEquatable. 
/// </summary>
/// <typeparam name="T">Any generic type.</typeparam>
public class TimeDelayQueue<T> : IEnumerable<TimeDelay<T>>, INotifyCollectionChanged
{
   /// <summary>
   /// Base queue object.
   /// </summary>
   private Queue<TimeDelay<T>> queue;

   /// <summary>
   /// Creates a time delayed queue.
   /// </summary>
   public TimeDelayQueue()
   {
       //Initialize queue
       queue = new Queue<TimeDelay<T>>();
   }

   /// <summary>
   /// Removes and returns the object at the beginning of the System.Collections.Generic.Queue of T.
   /// </summary>
   /// <returns>Generic T</returns>
   public T Dequeue()
   {
       //Output holder
       T output = default(T);

       //List of items that need to be requeued.
       List<TimeDelay<T>> requeueList = new List<TimeDelay<T>>();

       //While there is still item in the queue loop
       while (queue.Count > 0)
       {
           //Get the item
           TimeDelay<T> item = queue.Dequeue();

           //Check for no release
           if (item.Release == null)
           {
               output = item.Item;
               break;
           }
           else
           {
               //Check to see if release date has passed
               if (item.Release <= DateTime.Now)
               {
                   output = item.Item;
                   break;
               }
               else
               {
                   //Add to requeue list
                   requeueList.Add(item);
               }
           }
       }

       //Re-queue all items skipped for release date
       foreach (TimeDelay<T> item in requeueList)
       {
           queue.Enqueue(item);
       }

       //If output has value then notify collection changed
       if (output != null)
           CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List<TimeDelay<T>>() { { new TimeDelay<T>(output, null) } }));

       return output;
   }

   /// <summary>
   /// Adds an object to the end of the System.Collections.Generic.Queue of T. 
   /// </summary>
   /// <param name="item">Generic T</param>
   public void Enqueue(T item)
   {

       TimeDelay<T> output = new TimeDelay<T>(item, null);

       queue.Enqueue(output);

       if (CollectionChanged != null)
           CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<TimeDelay<T>>() { output }));
   }

   /// <summary>
   /// Adds an object to the end of the System.Collections.Generic.Queue of T. 
   /// </summary>
   /// <param name="item">Generic T</param>
   /// <param name="release">DateTime of release.</param>
   public void Enqueue(T item, DateTime? release)
   {
       TimeDelay<T> output = new TimeDelay<T>(item, release);

       queue.Enqueue(output);

       if (CollectionChanged != null)
           CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<TimeDelay<T>>() { output }));
   }

   /// <summary>
   /// Adds an object to the end of the System.Collections.Generic.Queue of T. 
   /// </summary>
   /// <param name="item">Generic T</param>
   /// <param name="waitMinutes">Minutes to wait before dequeue.</param>
   public void Enqueue(T item, int waitMinutes)
   {
       TimeDelay<T> output = new TimeDelay<T>(item, DateTime.Now.AddMinutes(waitMinutes));

       queue.Enqueue(output);

       if (CollectionChanged != null)
           CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<TimeDelay<T>>() { output }));
   }

   /// <summary>
   /// Creates a System.Collections.Generic.Queue of T from an System.Collections.Generic.IEnumereable of T
   /// </summary>
   /// <returns>List o TimeDelay of T objects.</returns>
   public List<TimeDelay<T>> ToList()
   {
       return queue.ToList<TimeDelay<T>>();
   }
   
   /// <summary>
   /// Removes all objects from System.Collections.Generic.Queue of T.
   /// </summary>
   public void Clear()
   {
       queue.Clear();

       if (CollectionChanged != null)
           CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
   }

   /// <summary>
   /// Determines whether an element is in System.Collections.Generic.Queue of T.
   /// </summary>
   /// <param name="item">Generic T</param>
   /// <returns>Flag indicating presence of item.</returns>
   public bool Contains(TimeDelay<T> item)
   {
       return queue.Contains(item);
   }

   /// <summary>
   /// Determines whether an element is in System.Collections.Generic.Queue of T.
   /// </summary>
   /// <param name="item">Generic T</param>
   /// <returns>Flag indicating presence of item.</returns>
   public bool Contains(T item)
   {
       return queue.Contains(new TimeDelay<T>(item, null));
   }

   /// <summary>
   /// Gets the number of elements contained in the System.Collections.Generic.Queue of T.
   /// </summary>
   public int Count
   {
       get { return queue.Count; }
   }

   /// <summary>
   /// Returns an enumerator that iterates through the System.Collections.Generic.Queue of T.
   /// </summary>
   /// <returns></returns>
   public IEnumerator<TimeDelay<T>> GetEnumerator()
   {
       return queue.GetEnumerator();
   }

   /// <summary>
   /// Returns an enumerator that iterates through the System.Collections.Generic.Queue of T.
   /// </summary>
   /// <returns></returns>
   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
   {
       return queue.GetEnumerator();
   }

   /// <summary>
   /// Returns an enumerator that iterates through the System.Collections.Generic.Queue of T.
   /// </summary>
   /// <returns></returns>
   IEnumerator<TimeDelay<T>> IEnumerable<TimeDelay<T>>.GetEnumerator()
   {
       return queue.GetEnumerator();
   }

   /// <summary>
   /// CollectionChanged event.
   /// </summary>
   public event NotifyCollectionChangedEventHandler CollectionChanged;
}


/// <summary>
/// Time Delay.
/// </summary>
/// <typeparam name="T">Any generic type.</typeparam>
public class TimeDelay<T> : IEquatable<TimeDelay<T>>
{
   /// <summary>
   /// DateTime of release from queue.
   /// </summary>
   public DateTime? Release { get; protected set; }

   /// <summary>
   /// Generic item in the queue.
   /// </summary>
   public T Item { get; set; }

   /// <summary>
   /// Holder for
   /// </summary>
   /// <param name="item">Generic T</param>
   /// <param name="release">DateTime of release.</param>
   public TimeDelay(T item, DateTime? release)
   {
       //Store data
       this.Item = item;
       this.Release = release;
   }

   /// <summary>
   /// Determines whether the specified TimeDelay object is equal to the current TimeDelay object.
   /// </summary>
   /// <param name="other"></param>
   /// <returns></returns>
   public bool Equals(TimeDelay<T> other)
   {            
       return this.Item.Equals(other.Item);            
   }
}

1 comment:

  1. Interesting code, but if it doesn't behave like a LIFO structure, can it really be a queue, strictly speaking ?

    Perhaps you should invent the 'Arr' structure !

    ReplyDelete