> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# C# Ref Struct

A `ref struct` is a custom value type in C# that is strictly constrained to be allocated only on the execution stack. The compiler enforces a rigorous set of rules to guarantee that instances of a `ref struct` can never escape to the managed heap, preventing them from being boxed, captured by closures, or embedded within heap-allocated objects.

```csharp theme={"dark"}
public ref struct StackOnlyData
{
    public int Id;
    public ReadOnlySpan<char> Buffer;
}
```

Because standard `struct` types can be promoted to the heap (e.g., when boxed, when used as a field in a `class`, or when captured in an asynchronous state machine), the `ref struct` modifier was introduced to provide a compiler-enforced guarantee of stack-only semantics.

## Compiler Constraints

To maintain the stack-only guarantee, the Roslyn compiler enforces the following structural and behavioral restrictions on any `ref struct`:

* **No Boxing:** A `ref struct` cannot be cast to `object`, `dynamic`, or `ValueType`.
* **Interface Restrictions:** While a `ref struct` *can* implement interfaces (as of C# 13), it cannot be cast or boxed directly to the interface type. It can only participate in interface dispatch through generic methods utilizing the `allows ref struct` anti-constraint.
* **Field Restrictions:** A `ref struct` cannot be declared as a field within a `class` or a standard `struct`. It can only be a field within another `ref struct`.
* **No Closures:** A `ref struct` cannot be captured by lambda expressions or local functions.
* **Asynchronous State Machines:** A `ref struct` cannot be declared as a local variable in an `async` method if it is held across an `await` boundary, because the compiler rewrites `async` methods into state machine objects that reside on the heap.
* **Iterators:** A `ref struct` cannot be held across a `yield return` boundary within an iterator method. As of C# 13, they are permitted as local variables in iterators as long as their lifetime does not span across the `yield` statement, which would require lifting them into a heap-allocated state machine.

## `ref` Fields (C# 11+)

A `ref struct` is the only type in C# permitted to declare `ref` fields. A `ref` field stores a managed pointer (an interior reference) to data, rather than the data itself. This restriction exists for lifetime safety: it prevents heap-allocated objects from holding pointers to stack-allocated variables. If a heap object held a reference to a stack variable, that reference would become a dangling pointer as soon as the stack frame unwinds.

```csharp theme={"dark"}
public ref struct PointerWrapper
{
    // Stores a reference to an integer, not the integer value
    public ref int NumberRef;
    
    // Stores a read-only reference to an integer
    public ref readonly int ReadOnlyNumberRef;
}
```

## Generic Anti-Constraints (C# 13+)

Historically, a `ref struct` could not be used as a generic type argument because generic types do not guarantee stack-only allocation. Starting in C# 13, a `ref struct` can be passed as a generic type argument if the generic parameter explicitly declares the `allows ref struct` anti-constraint. This forces the generic type or method itself to adopt `ref struct` allocation rules.

```csharp theme={"dark"}
// The 'allows ref struct' constraint permits T to be a ref struct
public ref struct GenericStackWrapper<T> where T : allows ref struct
{
    public T Data;
}

// Combining interface constraints with the anti-constraint
public void ProcessItem<T>(T item) where T : IDisposable, allows ref struct
{
    item.Dispose();
}
```

## `readonly ref struct`

A `ref struct` can be combined with the `readonly` modifier. This enforces immutability on the struct's fields while maintaining the stack-only allocation constraints.

In a `readonly ref struct`, all standard fields must be marked `readonly`. For `ref` fields, the field must be declared with the `readonly` modifier (`readonly ref T`). This ensures the reference itself cannot be reassigned to point to a different memory location. It does *not* require the referent (the underlying data) to be immutable, though you can optionally add `readonly` to the referent type (`readonly ref readonly T`) if strict deep immutability is required.

```csharp theme={"dark"}
public readonly ref struct ImmutableStackData
{
    public readonly int Length;
    
    // The reference cannot be reassigned, but the target integer CAN be modified
    public readonly ref int MutableTarget;
    
    // Neither the reference nor the target integer can be modified
    public readonly ref readonly int ImmutableTarget;
    
    public ImmutableStackData(int length, ref int mutableTarget, ref readonly int immutableTarget)
    {
        Length = length;
        MutableTarget = ref mutableTarget;
        ImmutableTarget = ref immutableTarget;
    }
}
```

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor C# Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
