DEV Community

Fabrizio Bagalà
Fabrizio Bagalà

Posted on • Edited on

Const and Readonly in C#

Immutability is a core concept in software development, offering numerous benefits including code predictability, easier reasoning, and reduced bugs. Languages like C# support immutability through several mechanisms, two of which are the const and readonly keywords.

Const

The const keyword is used to declare a constant, that is, a variable whose value cannot be changed after initialization. When declaring a constant, you must assign it a value.

public const int MyConstant = 10;
Enter fullscreen mode Exit fullscreen mode

In this example, MyConstant is a constant that has been initialized with the value 10. From this point onwards, the value of MyConstant cannot be changed at any other point in the code.

Readonly

The readonly keyword can be used in four contexts:

1️⃣ In a field declaration, readonly indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class.

public class MyClass
{
    private readonly int _myReadonlyVariable;

    public MyClass() 
    {
        _myReadonlyVariable = 10;
    }
}
Enter fullscreen mode Exit fullscreen mode

⚠️ Warning
An externally visible type that contains an externally visible read-only field that is a mutable reference type may be a security vulnerability and may trigger warning CA2104 : "Do not declare read only mutable reference types."

2️⃣ In a readonly struct type definition, readonly indicates that the structure type is immutable.

public readonly struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; init; }
    public double Y { get; init; }

    public override string ToString() => $"({X}, {Y})";
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ In an instance member declaration within a structure type, readonly indicates that an instance member does not modify the state of the structure.

Typically, you apply the readonly to the following kinds of instance members:

  • Methods:
public readonly double Sum()
{
    return X + Y;
}
Enter fullscreen mode Exit fullscreen mode

You can also apply the readonly to methods that override methods declared in System.Object:

public readonly override string ToString() => $"({X}, {Y})";
Enter fullscreen mode Exit fullscreen mode
  • Properties and indexers:
private int counter;
public int Counter
{
    readonly get => counter;
    set => counter = value;
}
Enter fullscreen mode Exit fullscreen mode

In C# 9.0 and later, you may apply the readonly to a property or indexer with an init accessor:

public readonly double X { get; init; }
Enter fullscreen mode Exit fullscreen mode

4️⃣ In a ref readonly method return, the readonly indicates that method returns a reference and writes are not allowed to that reference.

private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;
Enter fullscreen mode Exit fullscreen mode

Differences between const and readonly

Although const and readonly seem similar, there are some key differences between the two:

  • Initialization: A constant must be initialized at the time of declaration, whereas a readonly variable can be initialized at the time of declaration or in a constructor.
  • Type of value: A constant can hold only primitive or a null reference, whereas a readonly variable can hold any type of value.
  • Scope: Constants may have a global scope and can be used anywhere in the code, whereas readonly variables are confined within the class they are declared in.
  • Runtime vs compile time: Constants are evaluated at compile time, whereas readonly variables can be evaluated at runtime.

Conclusion

Understanding the functionalities and applications of const and readonly keywords is fundamental in C# programming. Both provide you with the ability to protect your variables from unintended changes, promoting code safety and predictability.

While constants are suitable for values that will never change, readonly variables provide a little more flexibility, as they can be assigned within constructors. This distinction makes readonly variables a perfect choice for values that are known at the time of object construction but are not known at compile time.

Remember, the right use of these keywords not only increases code readability and maintainability but also prevents potential bugs caused by inadvertent changes to these values. Always consider your specific use case, the nature of the values your variables will hold, and where and how they will be used within your code when choosing between const and readonly.

References

Top comments (6)

Collapse
 
ant_f_dev profile image
Anthony Fung

Very cool - I didn't know that readonly could be used in so many different ways.

Something to keep in mind is that while readonly fields can't be reassigned, they are still mutable. For example, a readonly List can still have entries added to it.

Collapse
 
fabriziobagala profile image
Fabrizio Bagalà

As you have seen, the readonly keyword can be used in several contexts. Your statement "readonly fields cannot be reassigned, but they are still editable" is true. Let me show you a simple example of what you said:

public class MyClass
{
    private readonly List<int> _myList;

    public MyClass()
    {
        _myList = new List<int>();
    }

    public void FillList()
    {
        _myList.Add(1);
        _myList.Add(2);
        _myList.Add(3);
    }

    public List<int> GetList()
    {
        return _myList;
    }
}

var myClass = new MyClass();
myClass.FillList();
var list = myClass.GetList();
Console.WriteLine(string.Join(' ', list)); // Prints "1 2 3"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
peledzohar profile image
Zohar Peled

This is a nice article but it has a mistake in it.
You wrote: "Constant variables have a global scope"
That's actually not true. A const has the scope it was declared in - it can be declared as a local const inside a method, or it can be declared as a class field and have the same scope as a static variable in that class.
constants can't have a global scope in c#.

Also, there's no such thing as a constant variable. It's either a constant or a variable, these are opposite terms.

Collapse
 
fabriziobagala profile image
Fabrizio Bagalà

Hi @peledzohar
Thank you for reading my article.

Constant variables have a global scope: This statement is not wrong, perhaps I should have put that "may have a global scope," and I will give you a practical example. Consider a library solution that you will use on multiple projects and that will contain the following class:

public static class TestConstant
{
    public const string Example = "This is an example";
}
Enter fullscreen mode Exit fullscreen mode

This class will be able to be used not only within the solution in which it is declared, but if an external project wants to use it, it can safely do so. So it can have a global scope.

Also, there's no such thing as a constant variable. It is either a constant or a variable, these are opposite terms: You find me in complete agreement that a variable and a constant are not the same thing and are opposite terms. I wanted to point to the fact that a constant is like a variable, although its operation is completely different, however I realize that this is not accurate.

In any case, I thank you for pointing out these inaccuracies 🙏

Collapse
 
peledzohar profile image
Zohar Peled

Fact of the matter is that a public const field is a lot like a public static readonly field, and they do have the same scope - however there are a couple of differences:

A const must have a value known in compile time. That is because the compiler will actually replace the const with it's value anywhere in your code - while a static field can be initialized at run time - i.e a value from an external configuration file or even a database.

That fact that a const must have a compile-time value limits the types that can be used for constants - for instance, you can't have a public const DateTime SomeDate... - that code will not compile. You can use any reference type you want for a const, but unless it's a string, it can only be initialized as null, even if your reference type does have an implicit conversion from a string.

Also, a static readonly field might be initialized either in the declaration or in the static constructor, while a const must be initialized in the declaration.

More information can be found in official documentation

Thread Thread
 
fabriziobagala profile image
Fabrizio Bagalà

Thank you very much for the clarification and for sharing the link to the official documentation 🙏