Comparing Init-Only, Get-Only, and Readonly in C# Code
Tags: csharp, dotnet
Published: 2022-11-01 19:39:05

---
title: Comparing Init-Only, Get-Only, and Readonly in C# Code
published: true
tags: csharp, dotnet
cover_image: https://newdevsguide.com/wp-content/uploads/2022/10/A_InitOnlyAndReadonly.png
# Use a ratio of 100:42 for best results.
# published_at: 2022-11-01 01:46 +0000
canonical_url: https://newdevsguide.com/2022/10/22/comparing-init-only-get-only-and-readonly-in-c-code/
---

Newer .NET developers are sometimes confused when they encounter readonly members in classes and the newer init-only setters. In this article we’ll explore both keywords along with the related get-only auto property. Finally, we’ll help you understand when to use each of these powerful language features.

## The C# Readonly Keyword

The [readonly keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) states that the field that it is applied to cannot be changed after the class is created.

Let’s take a look at a sample readonly field:

```csharp
private readonly int birthYear = 1998;
```

Here the `birthYear` field is given a value of 1998 and *cannot* be changed to a different value elsewhere in the class without generating a compiler error.

The advantages of the `readonly` keyword are the following:

- It makes it clearer that a value should never change
- It allows the compiler to make some performance optimizations knowing that the value will never change
- It can protect you from future mistakes if you need to make sure a value never changes.

I find myself using `readonly` frequently when a class manages a `List`, `Dictionary`, or other class to accomplish its goals.

**Important Note:** Many people incorrectly assume that `readonly` means that the object it is attached to becomes unchangeable or immutable. For example, they assume a `List<string>` defined as `readonly` cannot add new items to it. This is not the case. All `readonly` says is that the field holding the list cannot be updated to point to a *different* `List<string>` on the heap.

## Get-only Auto-Properties

Let’s talk briefly about get-only auto properties in C# because they’re really just a fancy way of using `readonly` under the hood.

Take a look at the following class that uses a get-only property called `Color`:

```csharp
public class Ball
{
  public Ball(string color)
  {
     this.Color = color;
  }

  public string Color {get;} // get-only auto-property
}
```

In this code, once the `Ball` is created, its `Color` property cannot be changed. This is because the code above is roughly equivalent to the following code:

```csharp
public class Ball
{
   private readonly string color;

   public Ball(string color)
   {
      this.color = color;
   }

   public string Color
   {
      get
      {
         return color;
      }
   }
}
```

Here we see that get-only auto properties automatically create a `readonly` field to manage their data.

## Init Only Setters

[Init-only setters](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/init) are a newer language feature that give you the ability to set read-only properties of a class at construction without needing to add constructor parameters.

Take the following class that doesn’t use init-only setters:

```csharp
public class Pet
{
   public Pet(string breed, int birthYear, string name)
   {
   }

   // Get-only auto properties
   public string Breed {get;}
   public int BirthYear {get;}
   public string Name {get;}
}
```

Here we can create a new `Pet` with code like the following:

```csharp
Pet myPet = new Pet("Cairn Terrier", 2016, "Jester");
```

This is fine, but as the number of properties we want to set grows, the number of parameters to the constructor has to grow too.

To help with this problem, C# gives us the option to use init-only property setters that can *only* be invoked when creating a class.

Here’s a version of `Pet` that takes advantage of init-only setters:

```csharp
public class Pet
{
   public string Breed {get; init;}
   public int BirthYear {get; init;}
   public string Name {get; set;}
}
```

Note that this class doesn’t declare a constructor beyond the default empty constructor. Admittedly this is a very simple class that perhaps should be a `stuct` or a `record`, but simple is fine for articles.

We could create an instance of `Pet` with the following code that provides an initializer after the constructor call:

```csharp
Pet myPet = new Pet()
{
   Breed = "Cairn Terrier",
   BirthYear = 2016,
   Name = "Jester"
};
```

This has the same effect as the code we saw before, but the initializer allows us to make our code more readable as the number of properties we need to initialize grows.

After the class is created, you will not be able to modify `Breed`, `BirthYear`, or `Name` because they are init-only.

Init-only setters are something that you might not use frequently, but they offer an alternative to passing large numbers of parameters to constructors, which can simplify your classes and make their creation more readable as well.

## Should I use Readonly, Get-only auto properties, or Init Only Setters?

Everything in this article is what I would consider to be an optional language feature of C#. You *can* use `readonly`, get-only auto properties, and init-only setters, but you never *have* to. Of course, all three of these language features will make your code more readable in its intent, slightly more performant, and can protect against undesired behavior for values you don’t want to change after creation.

If you do want to enforce that a value won’t change after an object is created, either `readonly`, a get-only auto property, or an init-only setter would work for you. So which one is right?

For me, I use the following decision-making process:

1. If I want to store a value but don’t need to expose it as a property, I use a `readonly` field.
2. If I have a small number of required attributes for a class and don’t expect that list to grow, I use a get only auto-property.
3. If I have a large number of properties I want to set or expect my property list to grow significantly over time, I use an init-only setter.

Bear in mind, as always, that the more features of a language you use the greater your code’s learning curve will be. This is especially true for newer and less-frequently used aspects of a language.

Still, these language features help your intent be more readable, your code more performant, and reduce the amount of boiler-plate you use in your codebases.

What do you and your team use, and why?