DEV Community

Cover image for Collection Initializers And Collection Expressions In C# – Simplified Code Examples
Dev Leader
Dev Leader

Posted on • Originally published at devleader.ca

Collection Initializers And Collection Expressions In C# – Simplified Code Examples

I was recently inspired by some interesting performance characteristics for collection initializers and collection expressions in C#, and I wanted to get an introductory article put together. This article will be part of a small series where I first introduce you to the syntax we have to work with for both collection expressions and collection initializers in C#. We’ll see the difference in style and readability — which the dotnet team has been progressing to make the language feel less heavy-handed while still maintaining expressiveness.

Once you’ve got a feel for how collection initializers and collection expressions in C# work, you’ll be geared up to check out some of the performance benchmarks on them. There’s no point in hyper-optimizing for this stuff unless you understand the basics!


Using List<T> with Collection Initializers in CSharp

Collection initializers in C# allow for a concise and readable way to populate collections like List<T> upon instantiation. This feature simplifies code by enabling the initialization of a collection with a set of predefined elements without the need for multiple calls to the Add method.

These next subsections will show examples of collection initializers with the List<T> type. Keep in mind that the entire point of these initializers is to define collections with elements in them to start with, which would save us from doing something like the following:

List<string> devLeaderCoolList = new List<string>();
devLeaderCoolList.Add("Hello");
devLeaderCoolList.Add(", ");
devLeaderCoolList.Add("World!");
Enter fullscreen mode Exit fullscreen mode

So with this as a starting point, consider that the upcoming examples make this feel more streamlined and concise.

Dev Leader Weekly | Substack

My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers.

favicon weekly.devleader.ca

Example 1: Initializing a List of Integers

List<int> primeNumbers = new List<int> { 2, 3, 5, 7, 11, 13, 17 };
Enter fullscreen mode Exit fullscreen mode

This example demonstrates initializing a List<int> with a collection of prime numbers. The numbers are enclosed in braces {} and separated by commas, directly following the instantiation of the list.

We can also use a slightly more short-hand syntax to drop the entire duplicated type definition from the right side of the equal sign:

List<int> primeNumbers = new() { 2, 3, 5, 7, 11, 13, 17 };
Enter fullscreen mode Exit fullscreen mode

Example 2: Combining Object and Collection Initializers

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

List<Student> students = new List<Student>
{
    new Student { Name = "Alice", Age = 22 },
    new Student { Name = "Bob", Age = 24 }
};
Enter fullscreen mode Exit fullscreen mode

Here, we combine object and collection initializers to create a List<Student> where each Student object is initialized with Name and Age properties. This approach streamlines the process of filling a collection with fully initialized objects. The important thing to pay attention to here is that the object initializer syntax is very much like the collection initializer syntax, but we are indeed doing two things:

  1. Assigning values to properties of new objects

  2. Assigning the collection elements upon collection creation

Example 3: Using Complex Expressions

List<double> areas = new List<double>
{
    Math.PI * Math.Pow(3, 2),
    Math.PI * Math.Pow(5, 2)
};
Enter fullscreen mode Exit fullscreen mode

This example initializes a List<double> with areas of circles (using πr²), where r is the radius. It illustrates that expressions, including method calls, can be used within collection initializers — that is, there is no restriction on constants or pre-evaluated values.

Example 4: Nested Collection Initializers

public class Classroom
{
    public List<Student> Students { get; set; }
}

List<Classroom> classrooms = new List<Classroom>
{
    new Classroom
    {
        Students = new List<Student>
        {
            new Student { Name = "Alice", Age = 22 }
        }
    },
    new Classroom
    {
        Students = new List<Student>
        {
            new Student { Name = "Bob", Age = 24 }
        }
    }
};
Enter fullscreen mode Exit fullscreen mode

This example shows how to use nested collection initializers to initialize a list of Classroom objects, each containing a list of Student objects. Very much like Example 2 that we looked at already, but this takes things up one more notch showing multiple collection initializers and object initialization as well.

Example 5: Simple List Initialization with Collection Expressions

In C# 11 we start to get some new fancier syntax for collection expressions. This was a step forward in reducing the verbosity of collection declarations using more shorthand similar to other languages. Microsoft says in their documentation:

You can use a collection expression to create common collection values. A collection expression is a terse syntax that, when evaluated, can be assigned to many different collection types. A collection expression contains a sequence of elements between [ and ] brackets.

Microsoft

Let’s check out an example:

List<int> evenNumbers = [2, 4, 6, 8, 10];
Enter fullscreen mode Exit fullscreen mode

This example demonstrates the straightforward initialization of a List<int> using the new collection expressions syntax, making the code more concise and readable.

Example 6: Combining Collections with Spread Operator

And there are even more goodies in C# 12 — we get the spread operator for collection initialization:

List<int> firstBatch = [1, 2, 3];
List<int> combinedList = [0, ..firstBatch, 4];
Enter fullscreen mode Exit fullscreen mode

Here, the spread operator .. is used to include elements from an existing collection (firstBatch) into a new list, showcasing the flexibility of the new syntax in combining collections seamlessly.


Where Are We Headed With These?

As you read through the various code examples, you can decide for yourself which ones offer you the readability that you prefer. There’s not necessarily a right or wrong answer here, but with variety and choice, we are likely going to need to make decisions within our teams about how to stay consistent. Try to strike a balance between minimizing redundancy without hiding too much type information!

But what’s next? Do we care THAT much about readability?

I mean, I do. Honestly, I think it’s incredibly important to prioritize readability in code. But if you’re curious like me, you might see a post like this from Dave Callan on the interwebs and get very curious:

Dave Callan - Collection Initializer Collection Expression Benchmarks

And since this is what sparked my interest and caused me to write this article as a primer, you’ll perhaps be interested in the performance characteristics that I investigated!


Wrapping Up CSharp Collection Initializers and Collection Expressions

Now that you’ve seen various examples of the syntax that we have access to, you can make your own informed decisions about which are most readable to you. I think it’s always important to spend some time looking at alternatives so that you can understand different perspectives, even if it seems like it might be minor. Odds are you’re going to read and write collection initializers and collection expressions MANY times in your software engineering career — so why not optimize your choice?

Speaking of optimizations… wait until you see the next article on the performance of collection initializers!

If you found this useful and you’re looking for more learning opportunities, consider subscribing to my free weekly software engineering newsletter and check out my free videos on YouTube! Meet other like-minded software engineers and join my Discord community!

Dev Leader Weekly | Substack

My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers.

favicon weekly.devleader.ca

Want More Dev Leader Content?

  • Follow along on this platform if you haven’t already!
  • Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: SUBSCRIBE FOR FREE
  • Looking for courses? Check out my offerings: VIEW COURSES
  • E-Books & other resources: VIEW RESOURCES
  • Watch hundreds of full-length videos on my YouTube channel: VISIT CHANNEL
  • Visit my website for hundreds of articles on various software engineering topics (including code snippets): VISIT WEBSITE
  • Check out the repository with many code examples from my articles and videos on GitHub: VIEW REPOSITORY

Top comments (2)

Collapse
 
jangelodev profile image
João Angelo

Hi Dev Leader,
Your tips are very useful
Thanks for sharing

Collapse
 
devleader profile image
Dev Leader

Glad you're enjoying! Thank you!!