readonly
Instance VariablesThe principle of least privilege is fundamental to good software engineering. In the context of an app, the principle states that code should be granted the amount of privilege and access needed to accomplish its designated task, but no more. Let’s see how this principle applies to instance variables.
Some instance variables need to be modifiable, and some do not. In Section 8.4, we used keyword const
to declare a constant, which must be initialized in its declaration—all objects of the class have the same value for that constant. Suppose, however, we want a constant that can have a different value for each object of a class. For this purpose, C# provides keyword readonly
to specify that an instance variable of an object is not modifiable and that any attempt to modify it after the object is constructed is an error. For example,
private readonly int
Increment;
declares readonly
instance variable Increment
of type int
. Like a constant, a readonly
variable’s identifier uses Pascal Case by convention. Although readonly
instance variables can be initialized when they’re declared, this isn’t required. A readonly
variable should be initialized by each of the class’s constructors or in the variable’s declaration. Each constructor can assign values to a readonly
instance variable multiple times—the variable doesn’t become unmodifiable until after the constructor completes execution. If a constructor does not initialize the readonly
variable, the variable uses the same default value as any other instance variable (0
for numeric simple types, false
for bool
type and null
for reference types)—these values actually are set before a constructor executes and can be overwritten by the called constructor.
Declaring an instance variable as readonly
helps enforce the principle of least privilege. If an instance variable should not be modified after the object is constructed, declare it to be readonly
to prevent modification.
const
members must be assigned values at compile time. Therefore, const
members can be initialized only with other constant values, such as integers, string
literals, characters and other const
members. Constant members with values that cannot be determined at compile time—such as constants that are initialized with the result of a method call—must be declared with keyword readonly
, so they can be initialized at execution time. Variables that are readonly
can be initialized with more complex expressions, such as an array initializer or a method call that returns a value or a reference to an object.
Attempting to modify a readonly
instance variable anywhere but in its declaration or the object’s constructors is a compilation error.
Attempts to modify a readonly
instance variable are caught at compilation time rather than causing execution-time errors. It’s always preferable to get bugs out at compile time, if possible, rather than allowing them to slip through to execution time (where studies have found that repairing bugs is often much more costly).
If a readonly
instance variable is initialized to a constant only in its declaration, it’s not necessary to have a separate copy of the instance variable for every object of the class. The variable should be declared const
instead. Constants declared with const
are implicitly static
, so there will only be one copy for the entire class.
readonly
Section 8.6.1 introduced C# 6’s getter-only auto-implemented properties. When an auto-implemented property has only a get
accessor, the property can be used only to read the value, so the compiler implicitly declares the corresponding private
instance variable as readonly
. Getter-only auto-implemented properties can be initialized in their declarations or in constructors.