Summary#
readonly marks a field that only the constructor may set:
class Booking {
public readonly string Reference;
public readonly int Seats;
public Booking(string reference, int seats) {
Reference = reference;
Seats = seats;
}
}Once the object exists, the field is settled — every other write is refused at compile time.
Signature#
readonly T Name; // set by a constructor
readonly T Name = value; // set at the declaration
public readonly T Name; // combines with any visibilityDescription#
The two places a readonly field may be assigned#
There are exactly two, and they are the same two as in C#:
- its own declaration —
public readonly decimal Rate = 0.25m; - a constructor of the class that declares it
class Invoice {
public readonly decimal Rate = 0.25m; // 1. at the declaration
public readonly string Number;
public Invoice(string number) {
Number = number; // 2. in the constructor
}
}Both values are ordinary per-instance data — read them like any other field:
[Test]
void ReadOnly_Fields_Hold_Their_Values() {
var i = new Invoice("INV-1");
Assert.Equal("INV-1", i.Number);
Assert.Equal(0.25m, i.Rate);
}Assigning it anywhere else is a compile error#
The refusals are the feature. None of these compile:
var i = new Invoice("INV-1");
i.Number = "INV-2"; // ✗ a write from outside
i.Rate += 0.1m; // ✗ `+=` is a write too
var j = new Invoice { Number = "x" }; // ✗ an object initializer runs after the constructor
class Invoice {
public void Renumber(string n) {
Number = n; // ✗ a METHOD of the same class — only a constructor may write
}
}The last one is worth pausing on: readonly narrows the write to constructors, not to the class. A method of the
declaring class is refused exactly like outside code.
A subclass constructor cannot write the base's field#
A field belongs to the class that declares it. By the time a derived constructor's body runs, the base has already
been constructed and its readonly fields are settled — so a subclass may write its own readonly fields and not
its base's:
class Badge {
public readonly string Tag;
public Badge(string tag) { Tag = tag; }
}
class Ranked : Badge {
public readonly decimal Rank;
public Ranked(string tag, decimal rank) : base(tag) {
Rank = rank; // its own — fine
}
}Writing Tag = "x" inside Ranked's constructor is a compile error: pass the value to base(…) instead, which is
what the example does.
readonly is not const#
They read similarly and mean different things:
const | readonly | |
|---|---|---|
| when the value is chosen | when the code is compiled | when the object is constructed |
| can it differ per instance | no — there is one value | yes — each new may pass a different one |
| what it may be initialized with | a compile-time constant | any expression the constructor can evaluate |
| is there a per-instance slot | no, uses are replaced by the value | yes, it is a real field |
Reach for const for a fixed number or name the whole program shares, and readonly for a value each instance is
given once and then keeps. Writing both on one field is a compile error — a const has no instance slot to protect.
readonly applies to a field, not a property#
A property has no storage of its own, so there is nothing for readonly to narrow. The property spellings that mean
the same things are:
{ get; }— an auto-property only a constructor may set{ get; init; }— settable during construction, including from an object initializer
public readonly decimal Area { get; set; } // ✗ readonly applies to a FIELD
public decimal Area { get; } // ✓ only the constructor sets it
public decimal Area { get; init; } // ✓ an object initializer may tooCan an entity field be readonly?#
readonly is a class modifier. An entity's fields are stored rows written by data operations, and what may write
them is declared in its security { } block rather than by a member modifier.
See also#
- class properties —
init,required, and the property forms that express single-assignment - constructor — the constructor, which is where a
readonlyfield gets its value - Classes — fields, defaults, and what a class is
- type visibility (public / internal) —
public,privateandprotected, which combine withreadonly