Use the readonly keyword as a modifier in five contexts:
In a field declaration,
readonlymeans you can only assign the field during the declaration or in a constructor in the same class. You can assign and reassign a readonly field multiple times within the field declaration and constructor.You can't assign a
readonlyfield after the constructor finishes. This rule affects value types and reference types differently:- Because value types directly contain their data, a field that is a
readonlyvalue type is immutable. - Because reference types contain a reference to their data, a field that is a
readonlyreference type must always refer to the same object. That object might not be immutable. Thereadonlymodifier prevents replacing the field value with a different instance of the reference type. However, the modifier doesn't prevent the instance data of the field from being modified through the read-only field.
- Because value types directly contain their data, a field that is a
In a
readonly structtype definition,readonlymeans the structure type is immutable. For more information, see thereadonlystruct section of the Structure types article.In an instance member declaration within a structure type,
readonlymeans an instance member doesn't modify the state of the structure. For more information, see thereadonlyinstance members section of the Structure types article.In a
ref readonlymethod return, thereadonlymodifier indicates that the method returns a reference and writes aren't allowed to that reference.- To declare a
ref readonlyparameter to a method.
- To declare a
ms.custom: "updateeachrelease"
The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.
The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.
Readonly field example
In this example, you can't change the value of the year field in the ChangeYear method, even though the class constructor assigns a value to it:
sample · csharpdocs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.csReadonlyField
using System;
using System.Collections.Generic;
using System.Text;
namespace Keywords
{
// <SnippetReadonlyField>
class Age
{
private readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}
// </SnippetReadonlyField>
// <SnippetInitReadonlyField>
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
// </SnippetInitReadonlyField>
public static class ReadonlyKeywordExamples
{
public static void Examples()
{
SamplePoint.Main();
ReadonlyRefReturns();
}
// <SnippetReadonlyReturn>
private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;
// </SnippetReadonlyReturn>
private static void ReadonlyRefReturns()
{
Console.WriteLine(Origin);
}
}
// <SnippetReadonlyRefReadonly>
public struct ReadonlyRefReadonlyExample
{
private int _data;
public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
{
// _data = 1; // Compile error if uncommented.
return ref reference;
}
}
// </SnippetReadonlyRefReadonly>
}You can assign a value to a readonly field only in the following contexts:
When you initialize the variable in the declaration, for example:
public readonly int y = 5;In an instance constructor of the class that contains the instance field declaration.
In the static constructor of the class that contains the static field declaration.
These constructor contexts are also the only contexts in which it's valid to pass a readonly field as an out or ref parameter.
sample · csharpdocs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.csInitReadonlyField
using System;
using System.Collections.Generic;
using System.Text;
namespace Keywords
{
// <SnippetReadonlyField>
class Age
{
private readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}
// </SnippetReadonlyField>
// <SnippetInitReadonlyField>
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
// </SnippetInitReadonlyField>
public static class ReadonlyKeywordExamples
{
public static void Examples()
{
SamplePoint.Main();
ReadonlyRefReturns();
}
// <SnippetReadonlyReturn>
private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;
// </SnippetReadonlyReturn>
private static void ReadonlyRefReturns()
{
Console.WriteLine(Origin);
}
}
// <SnippetReadonlyRefReadonly>
public struct ReadonlyRefReadonlyExample
{
private int _data;
public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
{
// _data = 1; // Compile error if uncommented.
return ref reference;
}
}
// </SnippetReadonlyRefReadonly>
}In the preceding example, if you use a statement like the following example:
p2.y = 66; // Erroryou get the compiler error message:
A readonly field cannot be assigned to (except in a constructor or a variable initializer)
Readonly instance members
Use the readonly modifier to declare that an instance member doesn't modify the state of a struct.
sample · csharpdocs/csharp/language-reference/builtin-types/snippets/shared/StructType.csSnippetReadonlyMethod
namespace builtin_types
{
public static class StructType
{
public static void Examples()
{
without_new.StructWithoutNew.Main();
parameterless_constructor.Example.Main();
field_initializer.Example.Main();
with_expression.Example.Main();
}
// <SnippetStructExample>
public struct Coords
{
public Coords(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
public override string ToString() => $"({X}, {Y})";
}
// </SnippetStructExample>
}
namespace without_new
{
// <SnippetWithoutNew>
public static class StructWithoutNew
{
public struct Coords
{
public double x;
public double y;
}
public static void Main()
{
Coords p;
p.x = 3;
p.y = 4;
Console.WriteLine($"({p.x}, {p.y})"); // output: (3, 4)
}
}
// </SnippetWithoutNew>
}
namespace readonly_struct
{
// <SnippetReadonlyStruct>
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})";
}
// </SnippetReadonlyStruct>
}
namespace readonly_members
{
public struct Example
{
// <SnippetReadonlyProperty>
private int counter;
public int Counter
{
readonly get => counter;
set => counter = value;
}
// </SnippetReadonlyProperty>
// <ReadonlyWithInit>
public readonly double X { get; init; }
// </ReadonlyWithInit>
public readonly double Y { get; init; }
// <SnippetReadonlyMethod>
public readonly double Sum()
{
return X + Y;
}
// </SnippetReadonlyMethod>
// <SnippetReadonlyOverride>
public readonly override string ToString() => $"({X}, {Y})";
// </SnippetReadonlyOverride>
}
}
namespace ref_struct
{
// <SnippetRefStruct>
public ref struct CustomRef
{
public bool IsValid;
public Span<int> Inputs;
public Span<int> Outputs;
}
// </SnippetRefStruct>
// <SnippetReadonlyRef>
public readonly ref struct ConversionRequest
{
public ConversionRequest(double rate, ReadOnlySpan<double> values)
{
Rate = rate;
Values = values;
}
public double Rate { get; }
public ReadOnlySpan<double> Values { get; }
}
// </SnippetReadonlyRef>
// <SnippetRefField>
public ref struct RefFieldExample
{
private ref int number;
public int GetNumber()
{
if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref number))
{
throw new InvalidOperationException("The number ref field is not initialized.");
}
return number;
}
}
// </SnippetRefField>
}
namespace parameterless_constructor
{
public static class Example
{
// <ParameterlessConstructor>
public readonly struct Measurement
{
public Measurement()
{
Value = double.NaN;
Description = "Undefined";
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public double Value { get; init; }
public string Description { get; init; }
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement();
Console.WriteLine(m1); // output: NaN (Undefined)
var m2 = default(Measurement);
Console.WriteLine(m2); // output: 0 ()
var ms = new Measurement[2];
Console.WriteLine(string.Join(", ", ms)); // output: 0 (), 0 ()
}
// </ParameterlessConstructor>
}
}
namespace field_initializer
{
public static class Example
{
// <FieldInitializer>
public readonly struct Measurement
{
public Measurement(double value)
{
Value = value;
}
public Measurement(double value, string description)
{
Value = value;
Description = description;
}
public Measurement(string description)
{
Description = description;
}
public double Value { get; init; }
public string Description { get; init; } = "Ordinary measurement";
public override string ToString() => $"{Value} ({Description})";
}
public static void Main()
{
var m1 = new Measurement(5);
Console.WriteLine(m1); // output: 5 (Ordinary measurement)
var m2 = new Measurement();
Console.WriteLine(m2); // output: 0 ()
var m3 = default(Measurement);
Console.WriteLine(m3); // output: 0 ()
}
// </FieldInitializer>
}
}
namespace with_expression
{
public static class Example
{
// <WithExpression>
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})";
}
public static void Main()
{
var p1 = new Coords(0, 0);
Console.WriteLine(p1); // output: (0, 0)
var p2 = p1 with { X = 3 };
Console.WriteLine(p2); // output: (3, 0)
var p3 = p1 with { X = 1, Y = 4 };
Console.WriteLine(p3); // output: (1, 4)
}
// </WithExpression>
}
}
namespace InlineArrays
{
// <DeclareInlineArray>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
// </DeclareInlineArray>
// <DeclareInlineArrayWithPointer>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithPointer
{
private unsafe char* _pointerElement; // CS9184
}
// </DeclareInlineArrayWithPointer>
// <DeclareInlineArrayWithReferenceType>
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBufferWithReferenceType
{
private string _referenceElement;
}
// </DeclareInlineArrayWithReferenceType>
}
}For more examples, see the readonly instance members section of the Structure types article.
Ref readonly return example
A readonly modifier on a ref return indicates that the returned reference can't be modified. The following example returns a reference to the origin. It uses the readonly modifier to indicate that callers can't modify the origin:
sample · csharpdocs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.csReadonlyReturn
using System;
using System.Collections.Generic;
using System.Text;
namespace Keywords
{
// <SnippetReadonlyField>
class Age
{
private readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}
// </SnippetReadonlyField>
// <SnippetInitReadonlyField>
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
// </SnippetInitReadonlyField>
public static class ReadonlyKeywordExamples
{
public static void Examples()
{
SamplePoint.Main();
ReadonlyRefReturns();
}
// <SnippetReadonlyReturn>
private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;
// </SnippetReadonlyReturn>
private static void ReadonlyRefReturns()
{
Console.WriteLine(Origin);
}
}
// <SnippetReadonlyRefReadonly>
public struct ReadonlyRefReadonlyExample
{
private int _data;
public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
{
// _data = 1; // Compile error if uncommented.
return ref reference;
}
}
// </SnippetReadonlyRefReadonly>
}The type returned doesn't need to be a readonly struct. Any type that ref can return can also be returned by ref readonly.
Readonly ref readonly return example
You can also use a ref readonly return with readonly instance members on struct types:
sample · csharpdocs/csharp/language-reference/keywords/snippets/ReadonlyKeywordExamples.csSnippetReadonlyRefReadonly
using System;
using System.Collections.Generic;
using System.Text;
namespace Keywords
{
// <SnippetReadonlyField>
class Age
{
private readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}
// </SnippetReadonlyField>
// <SnippetInitReadonlyField>
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
// </SnippetInitReadonlyField>
public static class ReadonlyKeywordExamples
{
public static void Examples()
{
SamplePoint.Main();
ReadonlyRefReturns();
}
// <SnippetReadonlyReturn>
private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;
// </SnippetReadonlyReturn>
private static void ReadonlyRefReturns()
{
Console.WriteLine(Origin);
}
}
// <SnippetReadonlyRefReadonly>
public struct ReadonlyRefReadonlyExample
{
private int _data;
public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
{
// _data = 1; // Compile error if uncommented.
return ref reference;
}
}
// </SnippetReadonlyRefReadonly>
}The method essentially returns a readonly reference together with the instance member (in this case a method) being readonly (not able to modify any instance fields).
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.