public async Task Test()
        {
            // Explicitly defined descending order of priorities
            QueuePriority[] descendingPriorities =
            {
                QueuePriority.Higher,
                QueuePriority.Normal,
                QueuePriority.Lower
            };

            var pQueue = new PriorityQueueNotifierUC <QueuePriority, string>(descendingPriorities);

            pQueue.Enqueue(QueuePriority.Lower, "1Lower");
            pQueue.Enqueue(QueuePriority.Higher, "1Higher");
            pQueue.Enqueue(QueuePriority.Normal, "1Normal");

            pQueue.Enqueue(QueuePriority.Lower, "2Lower");
            pQueue.Enqueue(QueuePriority.Normal, "2Normal");
            pQueue.Enqueue(QueuePriority.Higher, "2Higher");

            pQueue.Enqueue(QueuePriority.Lower, "3Lower");
            pQueue.Enqueue(QueuePriority.Higher, "3Higher");
            pQueue.Enqueue(QueuePriority.Normal, "3Normal");

            await Task.Run(() => Descending(pQueue));
        }
        private async Task Normal(PriorityQueueNotifierUC <QueuePriority, string> pQueue)
        {
            string dequeued;

            await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);            //awaiting first not required, TryDequeue can come first as well

            //Overriding priority in while cycles with awaiting can come with CPU heavy costs
            //if TryDequeue priority and EnqueuedItemsAsync priority are different or one method takes default descending priorities and other not
            while (!pQueue.TryDequeu(out dequeued, QueuePriority.Normal))
            {
                await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);
            }
            Assert.AreEqual("1Normal", dequeued);

            await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);            //awaiting first not required, TryDequeue can come first as well

            //Overriding priority in while cycles with awaiting can come with CPU heavy costs
            //if TryDequeue priority and EnqueuedItemsAsync priority are different or one method takes default descending priorities and other not
            while (!pQueue.TryDequeu(out dequeued, QueuePriority.Normal))
            {
                await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);
            }
            Assert.AreEqual("2Normal", dequeued);

            await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);            //awaiting first not required, TryDequeue can come first as well

            //Overriding priority in while cycles with awaiting can come with CPU heavy costs
            //if TryDequeue priority and EnqueuedItemsAsync priority are different or one method takes default descending priorities and other not
            while (!pQueue.TryDequeu(out dequeued, QueuePriority.Normal))
            {
                await pQueue.EnqueuedItemsAsync(QueuePriority.Normal);
            }
            Assert.AreEqual("3Normal", dequeued);
        }
        public async Task Test()
        {
            // Explicitly defined descending order of priorities
            QueuePriority[] descendingPriorities =
            {
                QueuePriority.Higher,
                QueuePriority.Normal,
                QueuePriority.Lower
            };

            var pQueue = new PriorityQueueNotifierUC <QueuePriority, string>(descendingPriorities);

            Task[] tasks =
            {
                Task.Run(() => Higher(pQueue)),
                Task.Run(() => Lower(pQueue)),
                Task.Run(() => Normal(pQueue))
            };

            //note: consumers will await enqueued data by producer(s) instead burning CPU cycles with TryDequeue on empty collection!!!

            pQueue.Enqueue(QueuePriority.Lower, "1Lower");
            pQueue.Enqueue(QueuePriority.Higher, "1Higher");
            pQueue.Enqueue(QueuePriority.Normal, "1Normal");

            pQueue.Enqueue(QueuePriority.Lower, "2Lower");
            pQueue.Enqueue(QueuePriority.Normal, "2Normal");
            pQueue.Enqueue(QueuePriority.Higher, "2Higher");

            pQueue.Enqueue(QueuePriority.Lower, "3Lower");
            pQueue.Enqueue(QueuePriority.Higher, "3Higher");
            pQueue.Enqueue(QueuePriority.Normal, "3Normal");

            await Task.WhenAll(tasks);
        }
        TestNotification(PriorityQueueNotifierUC <Priorities, Priorities> priorityQueues,
                         Queue <Priorities> dequeue)
        {
            while (priorityQueues.Count() > 0)
            {
                Priorities priorities;
                await priorityQueues.EnqueuedItemsAsync();

                if (!priorityQueues.TryDequeu(out priorities))
                {
                    continue;
                }
                dequeue.Enqueue(priorities);
            }
        }
        public void BasicFunctionality()
        {
            Priorities[] descendingPriorityOrder =
            {
                Priorities.Top,
                Priorities.Medium,
                Priorities.Bottom
            };

            PriorityQueueUC <Priorities, Priorities> priorityQueues =
                new PriorityQueueNotifierUC <Priorities, Priorities>(descendingPriorityOrder)
            ;

            priorityQueues.Enqueue(Priorities.Bottom, Priorities.Bottom);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Top, Priorities.Top);

            Priorities item;

            Assert.IsTrue(priorityQueues.TryDequeu(out item));
            Assert.AreEqual(item, Priorities.Top);

            Assert.IsTrue(priorityQueues.TryDequeu(out item));
            Assert.AreEqual(item, Priorities.Medium);

            Assert.IsTrue(priorityQueues.TryDequeu(out item));
            Assert.AreEqual(item, Priorities.Medium);

            Assert.IsTrue(priorityQueues.TryDequeu(out item));
            Assert.AreEqual(item, Priorities.Medium);

            Assert.IsTrue(priorityQueues.TryDequeu(out item));
            Assert.AreEqual(item, Priorities.Bottom);


            Assert.AreEqual(priorityQueues.Count(), 0);

            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            Assert.AreEqual(priorityQueues.Count(Priorities.Top), 0);
            Assert.AreEqual(priorityQueues.Count(Priorities.Medium), 1);
            Assert.AreEqual(priorityQueues.Count(Priorities.Bottom), 0);
        }
        public async Task BasicFunctionality()
        {
            PriorityQueueNotifierUC <Priorities, Priorities> priorityQueues =
                new PriorityQueueNotifierUC <Priorities, Priorities>(DescendingPriorityOrder)
            ;

            priorityQueues.Enqueue(Priorities.Bottom, Priorities.Bottom);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Top, Priorities.Top);
            priorityQueues.Enqueue(Priorities.Bottom, Priorities.Bottom);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Top, Priorities.Top);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            priorityQueues.Enqueue(Priorities.Top, Priorities.Top);

            Queue <Priorities> dequeue = new Queue <Priorities>();

            await TestNotification(priorityQueues, dequeue);

            Assert.AreEqual(dequeue.Dequeue(), Priorities.Top);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Top);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Top);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Medium);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Medium);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Medium);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Bottom);
            Assert.AreEqual(dequeue.Dequeue(), Priorities.Bottom);

            Assert.AreEqual(priorityQueues.Count(), 0);
            priorityQueues.Enqueue(Priorities.Medium, Priorities.Medium);
            Assert.AreEqual(priorityQueues.Count(), 1);

            Assert.AreEqual(priorityQueues.Count(Priorities.Top), 0);
            Assert.AreEqual(priorityQueues.Count(Priorities.Medium), 1);
            Assert.AreEqual(priorityQueues.Count(Priorities.Bottom), 0);

            await TestNotification(priorityQueues, dequeue);

            Assert.AreEqual(dequeue.Dequeue(), Priorities.Medium);
        }
        private async Task Descending(PriorityQueueNotifierUC <QueuePriority, string> pQueue)
        {
            string dequeued;

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("1Higher", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("2Higher", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("3Higher", dequeued);


            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("1Normal", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("2Normal", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("3Normal", dequeued);


            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("1Lower", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("2Lower", dequeued);

            await pQueue.EnqueuedItemsAsync();            //awaiting first not required, TryDequeue can come first as well

            //awaiting EnqueuedItemsAsync must match priority with TryDequeue, here default descending order, otherwise CPU cycles can be burned needlesly
            while (!pQueue.TryDequeu(out dequeued))
            {
                await pQueue.EnqueuedItemsAsync();
            }
            Assert.AreEqual("3Lower", dequeued);

            await Task.CompletedTask;
        }