Defensive Struct Copies & `readonly struct` Invariants
1Concept
Calling methods or properties on non-readonly structs passed with `in` causes the C# compiler to create a defensive copy of the struct in memory before the call to prevent possible mutations.
2Architecture Diagram
Non-Readonly Struct with `in`: Method Call ──> Compiler creates hidden temporary stack copy (Memory Waste!) `readonly struct` with `in`: Method Call ──> Direct pointer dereference with ZERO defensive copies!
3Code Example
C# 13 & .NET 9
using System;
// Immutable struct guarantees zero defensive copying
public readonly struct Vector3D
{
public readonly double X, Y, Z;
public Vector3D(double x, double y, double z) => (X, Y, Z) = (x, y, z);
public double MagnitudeSquared => X * X + Y * Y + Z * Z;
}
public class DefensiveCopyDemo
{
public static double CalculateDistance(in Vector3D v)
{
// Zero defensive copy because struct is declared 'readonly struct'
return v.MagnitudeSquared;
}
public static void Main()
{
var vec = new Vector3D(3.0, 4.0, 5.0);
Console.WriteLine($"Vector Magnitude Squared: {CalculateDistance(in vec)}");
}
}4Expected Output
Vector Magnitude Squared: 50
5Key Takeaways
- ✓Always mark immutable structs as `readonly struct`.
- ✓Never pass mutable structs with `in` parameter modifier.
- ✓Mark individual struct members as `readonly` if the entire struct cannot be readonly.