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;
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;
}
}
⚠️ 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})";
}
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;
}
You can also apply the readonly
to methods that override methods declared in System.Object
:
public readonly override string ToString() => $"({X}, {Y})";
- Properties and indexers:
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
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; }
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;
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
.
Top comments (6)
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, areadonly
List
can still have entries added to it.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: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.
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:
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 🙏
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
Thank you very much for the clarification and for sharing the link to the official documentation 🙏