Joydip Kanjilal
Contributor

How to use immutability in C#

how-to
Jun 29, 20207 mins
C#Microsoft .NETSoftware Development

Learn the importance of immutability and how to take advantage of it in your C# applications

artsy still life of bowling pins with green bowling ball
Credit: Thinkstock

Immutability is a feature of functional programming languages that makes programs easier to write, test, and maintain. However, immutability is not supported by many imperative programming languages. Until recently, C# did not support immutability out-of-the-box. 

That changes with the introduction of records in C# 9, which is available for preview in .NET 5. However, we can implement immutability in earlier versions of C# by using the System.Collections.Immutable namespace, which is available as a NuGet package. 

An immutable object is defined as an object that cannot be changed after it has been created. For many use cases, such as Data Transfer Objects, immutability is a desirable feature. This article discusses why we might want to take advantage of immutability and how we can implement immutability in C#.

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here

Create a .NET Core console application project in Visual Studio

First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next. 
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create. 

This will create a new .NET Core console application project in Visual Studio 2019. We’ll use this project to illustrate immutability in the subsequent sections of this article.

Install the System.Collection.Immutable NuGet package

To work with immutable types, you should install the System.Collections.Immutable package from NuGet. You can do this either via the NuGet package manager inside the Visual Studio 2019 IDE, or by executing the following command in the NuGet package manager console:

Install-Package System.Collections.Immutable

This package comprises a collection of thread-safe classes, also known as immutable collections.

Understand immutability and records in C# 9

A Data Transfer Object is a classic example of when you want immutability. An instance of a DTO is often serialized so that it can be independent of the technology used at the consumer end. Naturally, when transferring a data object between a database and a client, you would like to ensure that the object cannot be changed — and that is exactly the purpose of a DTO. You can read more about the use of Data Transfer Objects in C# from my earlier article here

To create immutable DTOs, you can take advantage of a ReadOnlyCollection or the thread-safe immutable collection types in the System.Collections.Immutable namespace. Alternatively, you could take advantage of record types in C# 9 to implement immutable DTOs.

A record type in C# 9 is a lightweight, immutable data type (or a lightweight class) that has read-only properties only. Since a record type is immutable, it is thread-safe and cannot mutate or change after it has been created.

You can initialize a record type only inside a constructor. Creating a record type for a class (Author in this example) is as simple as the following code snippet.

class data Author(int Id, string firstName, string lastName, string address);

You also could write the Author record type as shown in the code snippet given below:

public data class Author {
    public int Id { get; init; }
    public string firstName { get; init; }
    public string lastName { get; init; }
    public string address { get; init; }
}

Note the usage of the data keyword when declaring the record type. The data keyword when used in the declaration of a class marks the type as a record. You can take advantage of an instance of record type to pass data across the layers while at the same time ensuring immutability of the DTOs.

The System.Collections.Immutable namespace

Immutable collections are those whose members cannot change once they have been created. The System.Collections.Immutable namespace comprises several immutable collections. This namespace contains immutable versions of Lists, Dictionaries, Arrays, Hashes, Stacks, and Queues.

The ImmutableStack can be used to push and pop elements much the same way we do with mutable stacks. However, since ImmutableStack is an immutable collection, its elements cannot be altered. So, when you make a call to the pop method to pop an element from the stack, a new stack is created for you and the original stack remains unaltered.

Let’s illustrate this with an example. The following code snippet shows how you can push elements onto an immutable stack.

var stack = ImmutableStack<int>.Empty;
for(int i = 0; i < 10; i++)
{
    stack = stack.Push(i);
}

The following program demonstrates that the elements of an immutable stack cannot be altered.

class Program
    {      
        static void Main(string[] args)
        {
            var stack = ImmutableStack<int>.Empty;
            for(int i = 0; i < 10; i++)
            {
                stack = stack.Push(i);
            }
            Console.WriteLine("No of elements in original stack:
             "+stack.Count());
            var newStack = stack.Pop();
            Console.WriteLine("No of elements in new stack: " +
            newStack.Count());
            Console.ReadKey();
        }
    }

When you execute the above program, here’s how the output should appear in the console window.

csharp immutability IDG

Figure 1

As you can see in Figure 1, the original immutable stack (containing 10 elements) is unchanged after a call to the Pop() method. Rather, a new immutable stack is created with 9 elements.

Immutable collections don’t offer constructors but you can take advantage of the static factory method called Create as shown in the code snippet given below.

var list = ImmutableList.Create(1, 2, 3, 4, 5);

If you wanted to add or remove an element from this collection, a new immutable list would be created and the original immutable list would remain unchanged.

Immutability is a design choice; it means that an instance of a type cannot be changed after it has been created. Except for immutable stacks and immutable queues, all immutable collections are based on AVL trees. Hence you can insert elements at any position of the collection, i.e., the beginning, middle, or end, without needing to copy the tree in its entirety.

How to do more in C#:

Joydip Kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author