Author avatar

Dániel Szabó

Benefits of Read-Only Coding in C#

Dániel Szabó

  • Feb 24, 2020
  • 6 Min read
  • 1,286 Views
  • Feb 24, 2020
  • 6 Min read
  • 1,286 Views
Languages Frameworks and Tools
C#

Introduction

Most languages support read-only programming or coding with keywords, literals, operators, etc. It is, however, a very divisive subject. Some people start developing in C# as their first language, while others jump to this language with development experience in other languages. The result is differing presumptions about this coding style.

In this guide, we will see what read-only coding boils down to in C# and how you can safely utilize it to your advantage. There are two keywords that support read-only programming, const and readonly, and we will break down each of them, then assemble a small app for demonstration.

const

With the help of the const keyword, we are able to declare a constant field or constant local. These are not treated as variables and they cannot be modified; their value stays intact during the whole execution cycle. We should avoid creating constants for storing information we expect to change over time, because when the change happens, an exception will stop us.

There are four types of constants:

  1. Number
  2. String
  3. Bool
  4. Null reference

You may declare your constants in C# the following way.

1
2
3
4
const int a = 10;
const string b = "My Constant!";
private const string Name = "Daniel";
private const int Salary = 100000;
csharp

You also have the option to declare multiple constants on the same line.

1
const double a = 1.0, b = 2.0, c = 3.0;
csharp

Due to the restrictions the const implies and also forces upon the developer, a new keyword was introduced.

readonly

The 'readonly' modifier can be used in a total of four contexts:

  1. Field declaration
  2. Readonly struct declaration
  3. Readonly member definition
  4. Ref read only method return

When we use the field declaration context, we need to know that the only time the assignment can occur is when it is declared or when the constructor of the same class is invoked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

namespace Pluralsight
{
    public class ReadOnlyProgramming
    {
        readonly string Name;
        readonly int Age;
        readonly int Salary;
        public ReadOnlyProgramming()
        {
            Name = "Default Name";
            Age = 99;
            Salary = 10000;
        }
        public ReadOnlyProgramming(string name, int age, int salary)
        {
            Name = name;
            Age = age;
            Salary = salary;
        }
        public static void Main()
        {
            ReadOnlyProgramming a = new ReadOnlyProgramming();
            ReadOnlyProgramming b = new ReadOnlyProgramming("Florian", 28, 200000);

            Console.WriteLine($"The variable: {nameof(a)} holds: {a.Name} with age: {a.Age} and salary: {a.Salary} USD/yr !");
            Console.WriteLine($"The variable: {nameof(b)} holds: {b.Name} with age: {b.Age} and salary: {b.Salary} USD/yr !");
            //a.Name = "Naomi"; // uncommenting this results in an error
            Console.ReadKey();
        }
    }
}
csharp

The following output is produced when the code executes.

1
2
The variable: a holds: Default Name with age: 99 and salary: 10000 USD/yr !
The variable: b holds: Florian with age: 28 and salary: 200000 USD/yr !
bash

We have two constructors in our class. One without argument sets a default value for the readonly properties after it is called, and the second constructor takes three arguments and initializes the properties with them. This is allowed, but if we were to modify any of the properties marked with readonly after the instance is created, the following error would welcome us.

1
A readonly field cannot be assigned to (except in a constructor or a variable initializer)
bash

When we use the readonly struct context, the rule is that we will have an immutable struct where all the instance fields need to be marked as readonly, otherwise the following error welcomes us.

1
Instance fields of readonly structs must be readonly.
bash

Let's create a struct to store static server information about our infrastructure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;

namespace Pluralsight
{
    public readonly struct Server
    {
        public readonly string Name;
        public readonly string Location;
        public readonly string OS;
        public readonly int vCPU;
        public readonly int RAM;

        public Server(string name, string location, string os, int vcpu, int ram)
        {
            Name = name;
            Location = location;
            OS = os;
            vCPU = vcpu;
            RAM = ram;
        }

    public override string ToString() => $"(Name: {Name}, Location: {Location}, Operating System: {OS}, vCPU: {vCPU}, RAM: {RAM} GB)";
    }

    public class ReadOnlyProgramming
    {
        public static void Main()
        {
            Server a = new Server("Domain Controller","Amsterdam","Centos 7.6",8,16);
            Console.WriteLine(a.ToString());
            Console.ReadKey();
        }
    }
}
csharp

The output produced is as follows.

1
(Name: Domain Controller, Location: Amsterdam, Operating System: Centos 7.6, vCPU: 8, RAM: 16 GB)
bash

There are two important concepts here. We cannot add new property without making it read-only. This prevents the data from being modified, and we cannot alter the existing properties, either.

When we use the readonly member context, we have the option to apply the keyword on members. We cannot apply it on class or interface member declarations, however. There are two rules you need to remember:

  1. Static methods or properties cannot be read-only.
  2. Constructors cannot be read-only.

A small demonstration of a read-only member for our above example would be.

1
public readonly DateTime InstallDate { get; }
csharp

The ref readonly context is a bit more complicated, and it involves pointers and unsafe code. The modifier applied on ref means that the returned reference cannot be modified. Any type that can be returned by ref can have the read-only modifier applied to it.

Conclusion

Read-only coding is all about securing information in either class fields or structs. Making sure we do not allow tampering with data is an ever-growing concern in our digital world. C# has the necessary features to help you write secure applications. I hope this guide has been informative to you and I would like to thank you for reading it!

13