Let's say we want to implement a simple message queue of FIFO type. Messages get registered with message processor and they get handled in their own turn. You could write a List<Message>, but that would be inefficient. If we add Message-s at the end of a list and consume them at the front, the whole queue would have to be shifted element by element as the front is consumed, and that's slow.

A little less naive implementation would be to use LinkedList<Message> and consume the top while adding the new ones to the bottom. This would cause the elements to be constantly allocated.

You want the data structure called RingBuffer, an array of continual elements in memory that has a Head and a Tail. New elements are added to the Tail position, so it fills from tail to the right and empties from head to the right. Once the tail reaches the end, it starts from the first element. If it "catches up" with head it is considered an overflow condition, most commonly handled by doubling its size. The list is pre-allocated and elements are initialized to default(T). Used elements are not de-allocated but stay in the list and are overwritten when tail has caught up to them.

You can read more details here.

You could also use a Queue<Message> and I certainly have, but then you don't get the access to the implementation so you are missing some options: Once the queue runs out of elements, should it expand, drop an element, throw an exception or override the front element? With .NET implementation you get the expansion as mandatory.

Lastly, you can use my implementation posted here.

If you're finding this article helpful, consider our asset Dialogical on the Unity Asset store for your game dialogues.