Pass-by-Reference: `ref`, `out`, `in` & `ref readonly` Semantics
1Concept
`ref` passes a pointer to the variable allowing read/write. `out` mandates caller assignment before return. `in` passes a reference as readonly to eliminate struct copy overhead. `ref readonly` guarantees immutability.
2Architecture Diagram
Pass-by-Value: [ Caller Stack: Struct (128B) ] ──Copy 128 Bytes──> [ Callee Stack: Copy (128B) ] Pass-by-Reference (`in` / `ref readonly`): [ Caller Stack: Struct (128B) ] <──8-Byte Pointer── [ Callee: Direct Access (0B Copy) ]
3Code Example
C# 13 & .NET 9
using System;
public struct LargeMatrix128Bytes
{
public long M1, M2, M3, M4, M5, M6, M7, M8;
}
public class RefSemanticsDemo
{
// Zero-copy readonly parameter
public static long ComputeSum(in LargeMatrix128Bytes matrix)
{
// matrix.M1 = 99; // COMPILE ERROR: Readonly variable
return matrix.M1 + matrix.M2;
}
public static void Main()
{
var mat = new LargeMatrix128Bytes { M1 = 100, M2 = 200 };
long sum = ComputeSum(in mat);
Console.WriteLine($"Computed Sum without struct copy: {sum}");
}
}4Expected Output
Computed Sum without struct copy: 300
5Key Takeaways
- ✓Use `in` for structs > 16 bytes to eliminate defensive stack copying.
- ✓`out` parameters are ideal for TryParse patterns returning status and payload.
- ✓`ref readonly` returns protect internal arrays/buffers while giving direct pointer performance.