Improve Readability of Your Code with C# Collection Expressions

C# 12 introduced one interesting feature called collection expressions.
Collection expressions allow writing more concise and readable code when working with collections.

In today’s blog post, you will learn about collection expression initializers, various expression usages and the spread element.

On my website: antondevtips.com I share .NET and Architecture best practices.
Subscribe to become a better developer.

Collection Initializers

Collection expressions provide a simple and consistent syntax across many different collection types.
When initializing a collection with a collection expression, the compiler generates code that is functionally equivalent to using a collection initializer.

Let’s explore the usual ways to initialize a list:

// Using var
var list1 = new List<int> { 1, 2, 3, 4, 5 }; // Or using new()
List<int> list2 = new() { 1, 2, 3, 4, 5 };
Enter fullscreen mode Exit fullscreen mode

Collection expressions provide a new syntax to initialize collections:

List<int> list = [ 1, 2, 3, 4, 5 ];
Enter fullscreen mode Exit fullscreen mode

You can also replace the usual array initialization:

var array1 = new int[5] { 1, 2, 3, 4, 5 }; var array2 = new int[] { 1, 2, 3, 4, 5 }; var array3 = new[] { 1, 2, 3, 4, 5 };
Enter fullscreen mode Exit fullscreen mode

With a new syntax:

int[] array = [ 1, 2, 3, 4, 5 ];
Enter fullscreen mode Exit fullscreen mode

When using a new syntax, you need to specify a concrete type of collection, as it can’t be inferred directly from the collection initialization.

You can use this new collection expression initialization for collections of any type.
Let’s explore a few examples:

char[] letters = [ 'a', 'b', 'c', 'd' ]; List<string> names = [ "Anton", "Bill", "John" ]; List<Person> persons = [ new("Anton", 30), new("Bill", 25), new("John", 20)
];
Enter fullscreen mode Exit fullscreen mode

Personally, I like this new syntax, it makes code more concise and more readable for me.

Initializing Empty Collections

You can use a new syntax to initialize empty collections in a new more concise and readable way.

Here is the most common approach to initialize an empty array and list:

var emptyArray = new int[0] {}; var emptyList = new List<int>();
Enter fullscreen mode Exit fullscreen mode

When using this approach, you allocate memory to create an empty collection.
So instead, you can use the following initializers that don’t allocate any memory at all:

var emptyArray = Array.Empty<int>(); var emptyList = Enumerable.Empty<int>();
Enter fullscreen mode Exit fullscreen mode

But you can replace all these with a new empty collection expression initializer:

int[] emptyArray = []; List<int> emptyList = [];
Enter fullscreen mode Exit fullscreen mode

This approach is more concise and readable and moreover, the compiler translates it to using Array.Empty<T> and Enumerable.Empty<T> under the hood, so you don’t need to worry about memory.

Using a Spread Element

The spread element (.. two dots) allows you to include the elements of one collection into another collection concisely.
This feature is particularly useful when you want to combine or merge collections.

Let’s say you have two arrays of numbers, and you want to combine them into a single array:

int[] oneTwoThree = [1, 2, 3];
int[] fourFiveSix = [4, 5, 6]; int[] allNumbers = [..oneTwoThree, 50, 60, ..fourFiveSix]; Console.WriteLine(string.Join(", ", allNumbers));
Console.WriteLine($"Length: {allNumbers.Length}");
Enter fullscreen mode Exit fullscreen mode

This will output the following result:

1, 2, 3, 50, 60, 4, 5, 6
Length: 8
Enter fullscreen mode Exit fullscreen mode

It doesn’t end up with numbers, you can combine any objects you want, for example, strings:

string[] greetings = ["Hello", "Hi"];
string[] farewells = ["Goodbye", "See you"]; string[] allMessages = [..greetings, "How are you?", ..farewells]; Console.WriteLine(string.Join(", ", allMessages));
Console.WriteLine($"Length: {allMessages.Length}");
Enter fullscreen mode Exit fullscreen mode

That outputs:

Hello, Hi, How are you?, Goodbye, See you
Length: 5
Enter fullscreen mode Exit fullscreen mode

And objects:

Person[] groupA =
[ new Person("John", 20), new Person("Jane", 22)
]; Person[] groupB =
[ new Person("Alice", 25), new Person("Bob", 27)
]; Person[] allPeople = [..groupA, new Person("Charlie", 30), ..groupB]; foreach (var person in allPeople)
{ Console.WriteLine(person);
}
Enter fullscreen mode Exit fullscreen mode

That outputs:

Person { Name = John, Age = 20 }
Person { Name = Jane, Age = 22 }
Person { Name = Charlie, Age = 30 }
Person { Name = Alice, Age = 25 }
Person { Name = Bob, Age = 27 }
Enter fullscreen mode Exit fullscreen mode

This approach is really nice to read and it is easier to write such code than manually creating a list that combines all the values.

This reminds me of a spread operator in JavaScript and TypeScript, but in C# it’s not that powerful yet.
And in C# it’s not an operator but an element.
Hope it will be further improved in the future and will allow us to combine objects with a spread syntax.

Summary

Collection expressions are a great feature introduced in C# 12.
You can use collection initializers and spread element to write more concise and readable code when working with collections.

In your team, you have to decide whether to adapt this feature or not.
But for me, this feature is a complete win comparing to the old ways of working with collections.

On my website: antondevtips.com I share .NET and Architecture best practices.
Subscribe to become a better developer.


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top