Skip to content

Queues in C#

Queues in C#

In this article, I explain what queues are and how to use Queues in C#. Have you ever waited in line to buy tickets for a popular movie or event? If so, you have experienced a real-life example of a queue. The first person in line is the first to buy a ticket, and as people join the line, they do so at the end. When someone buys a ticket and leaves the line, the next person in line becomes the first in line and can buy a ticket. This is an example of the first in, first out (FIFO) principle that a queue follows. You can also learn about binary trees in this article.

Creating a Queue

C# provides a built-in class named Queue that implements this data structure. To create a queue in C#, you need to instantiate the Queue class, as shown below:

This creates an empty queue that can store elements of string type. You can also initialize a queue with some elements:

This creates a queue of integers with four elements: 1, 2, 3, and 4.

There’s also a non-generic implementation of queue built into C#:

The non-generic implementation works with objects.

Adding Elements to a Queue

To add an element to the end of the queue, you can use the Enqueue method:

This adds the string “element” to the end of the queue.

Removing Elements from a Queue

To remove the element at the beginning of the queue, you can use the Dequeue method:

This removes the first element from the queue and returns it. If the queue is empty, it’ll throw an InvalidOperationException.

Putting it Together

Let’s simulate the tickets queue example from the intro using code.

And the result is:

Let’s move on.

Retrieving the Element at the Beginning of the Queue

To retrieve the element at the beginning of the queue without removing it, you can use the Peek method, as shown below:

This returns the first element of the queue without removing it. If the queue is empty, it throws an InvalidOperationException.

Checking if a Queue Contains an Element

To check if a queue contains a specific element, you can use the Contains method, as shown below:

This returns a boolean value indicating whether the queue contains the specified element. You know how it works now. Let’s see how you can use queues in your real-world apps.

Example: Message Queues

There are times when different system components need to exchange messages without coupling to each other. In these scenarios, a queue can be used to facilitate this exchange by acting as a buffer between the components. Messages can be added to the queue by one component and retrieved by another, allowing the components to communicate without being aware of each other’s internal workings. This can make your code more modular and easier to maintain.

Here’s an example of a simple messaging system that uses a queue in C#:

Let’s use our messaging system before discussing how it works.

In this example, the MessagingSystem class has a private messageQueue field that is used to store messages sent by users. The SendMessage method adds messages to the end of the queue using the Enqueue method. The ReceiveMessage method removes the first message from the queue using the Dequeue method and returns it. If the queue is empty, it prints a message to the console and returns null.

The Message class is a simple class that represents a message sent by a user. It has three properties: Sender, Recipient, and Body.

In the example usage code, we create a new MessagingSystem object and send two messages using the SendMessage method. We then receive the messages using the ReceiveMessage method and print their contents to the console. Finally, we try to receive another message when the queue is empty, which prints a message to the console.

Notice that we used the non-generic Queue class. You can also validate the subscriber in the ReceiveMessage method. Now imagine a proxy that decorates the queue class and transmits the queued items on TCP, and retrieves messages from the network before queueing them. By the way, did you know that we offer a unique online course that boosts your C# career? Check it out here!

Asynchronous Logging

Queues can also be used to implement a logging system in some scenarios. For example, you could use a queue to buffer log messages before writing them to a file or database. This can help improve performance by reducing the number of writes to the file or database and can also make the logging system more resilient to failures.

Here’s an example of how you could use a queue to implement a simple logging system in C#:

Let’s also use our logger before discussing the mechanics.

As the result, the logger has written the logs in the <app-path>/log.txt file:

In this example, the Logger class has a private logQueue field used to store log messages. The Log method adds messages to the end of the queue using the Enqueue method. The Flush method writes all the messages in the queue to a log file specified by the logFilePath parameter. It does this by opening the log file in append mode using a StreamWriter object and then writing each log message to a new line in the file using the WriteLine method.

The LogMessage class is a simple class that represents a log message. It has two properties: Timestamp, which is a DateTime object representing the time the message was logged, and Message, which is a string containing the log message.

In the example usage code, we create a new Logger object and log two messages using the Log method. We then flush the messages to the log file using the Flush method. You can also read more about stacks in this article.

Queues Use Cases

Queues are useful for scenarios where you need to process items in the order they were added. Some common use cases for queues include:

  • Message queues: Queues can be used to facilitate communication between different components of a system. For example, one component could add messages to a queue, and another component could read messages from the queue and process them.
  • Job queues: Queues can be used to manage a list of tasks that need to be executed. For example, a web server might use a queue to manage incoming requests, processing each request in the order it was received.
  • Event queues: Queues can be used to manage a list of events that need to be processed. For example, a game might use a queue to manage user input, processing each input event in the order it was received.
  • Cache Queues: Queues can also be used to implement a cache. A cache is a temporary storage area used to store frequently accessed data. By using a queue to manage the cache, you can ensure that the most recently accessed items are kept in the cache while older items are removed.
  • Thread Pools: A thread pool is a collection of worker threads that can be used to execute tasks in parallel. By using a queue to manage the tasks, you can ensure that they are executed in the order they were received and that no more than a certain number of tasks are executed concurrently.

Queues are a useful data structure that can simplify many programming tasks. They are commonly used in scenarios where items need to be processed in the order they were added, such as message queues, job queues, and event queues. Queues can also be used to implement a cache, a thread pool, and other useful features. If you want to skyrocket your C# career, check out our powerful ASP.NET full-stack web development course that also covers test-driven development.

Conclusion

Queues are a useful data structure that can simplify many programming tasks. C# provides a built-in Queue class that makes it easy to create and manipulate queues in your code. By using the methods provided by the Queue class, you can perform operations such as adding and removing elements, retrieving the element at the beginning of the queue and checking if a queue contains a specific element.

Enter your email and we will send you the PDF guide:
Enter your email and we will send you the PDF guide