One of the more convenient introductions in C# 12 and .NET 8 is collection expressions.

Typically, you would create and initialize a List<T> as follows:

var list = new List<int> { 1, 2, 3, 4, 5 };

Similarly, an array would be created and initialized as follows:

var array = new int[] { 1, 2, 3, 4, 5 };

With collection expressions, these can be rewritten as follows:

List<int> list = [1, 2, 3, 4, 5];

Similarly, for the array:

int[] array = [1, 2, 3, 4, 5];

As you can see, the initialization of the collections is identical, regardless of the collection type.

This means that you can do the same for an IEnumerable<T>

IEnumerable<int> array = [1, 2, 3, 4, 5];

Or a ConcurrentBag<T>

ConcurrentBag<int> bag = [1, 2, 3, 4, 5];

For a Stack<T> and Queue<T>, collection initializers don’t quite work as is, but they help make it easier by taking advantage of their constructor overloads that accept collections.

Stack<int> stack = new([1, 2, 3, 4, 5]);
	
Queue<int> queue = new([1, 2, 3, 4, 5]);

Collection expressions also work for the Dictionary.

var dict = new Dictionary<int, string>
{
  [1] = "One",
  [2] = "Two",
  [3] = "Three"
};

You can also write this as follows:

Dictionary<int, string> dict = new()
{
  [1] = "One",
  [2] = "Two",
  [3] = "Three"
};

This even works for dictionaries with complex types.

Assuming we have this type:

public record Agent(string Name);

You can initialize a dictionary as follows:

Dictionary<int, Agent> dict = new()
{
  [1] = new Agent("James Bond"),
  [2] = new Agent("Vesper Lynd"),
  [3] = new Agent("Eve Moneypenny"),
};

TLDR

Collection initializers make it easy to create and initialize various collections.

Happy hacking!