WHY?
In .NET, structs are value types, and when you mark a struct as readonly, it promises that the struct's internal state cannot change after it’s created. However, structs can have methods that modify their fields or internal state.
When a readonly struct is accessed, .NET needs to make sure this immutability promise is kept. If you call a method on a readonly struct that could modify its internal state, the runtime creates a defensive copy to protect the original struct.
Immutability Guarantee: Without the defensive copy, calling a method like MutatingMethod could break the immutability contract of a readonly struct.
Safety for Consumers: It protects the developer from unintended side effects caused by struct methods.
For example:
readonly struct MyStruct
{
public int X { get; }
public MyStruct(int x) => X = x;
public void MutatingMethod()
{
// Hypothetically mutating the state
Console.WriteLine("Mutating...");
}
}
readonly MyStruct myStruct = new MyStruct(10);
myStruct.MutatingMethod(); // Defensive copy happens here
When myStruct.MutatingMethod() is called, a defensive copy of myStruct is made before invoking MutatingMethod. This ensures that the original myStruct stays unchanged, preserving its immutability.
Readonly Fields Accessing methods or properties on a readonly struct field triggers a copy:
class Example { private readonly MyStruct _myStruct;
public void DoSomething()
{
_myStruct.MutatingMethod(); // Defensive copy is created
}
}
Readonly Parameters Passing a readonly struct as an in parameter can also result in defensive copies if the struct’s method or property mutates the struct:
void ExampleMethod(in MyStruct myStruct)
{
myStruct.MutatingMethod(); // Creates a copy of myStruct
}
Read more about on Microsoft Docs on readonly structs which explains how readonly enforces immutability and when defensive copies occur -> https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#readonly-struct