Skip to content

C# Ref Return — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# Ref Return. We cover key concepts, practical examples, and best practices.

A method returns a value from an array or a large struct. Every call copies the value. If you want to modify the original or avoid the copy, you previously used unsafe code or out parameters. Ref returns let you return a reference to the original location.

Wrong

public int GetMax(int[] numbers)
{
    int maxIndex = 0;
    for (int i = 1; i < numbers.Length; i++)
        if (numbers[i] > numbers[maxIndex]) maxIndex = i;
    return numbers[maxIndex]; // Returns a copy
}

Output: Returns the max value. Caller cannot modify the array through this method.

public ref int GetMax(int[] numbers)
{
    int maxIndex = 0;
    for (int i = 1; i < numbers.Length; i++)
        if (numbers[i] > numbers[maxIndex]) maxIndex = i;
    return ref numbers[maxIndex]; // Returns a reference
}

// Usage
ref int max = ref GetMax(scores);
max = 100; // Modifies scores[maxIndex] directly!
Console.WriteLine(scores[2]); // 100

Output: The array element is modified through the reference. No copying.

Ref returns can also avoid copying large structs:

public ref readonly LargeStruct GetItem(int index)
{
    return ref _items[index]; // Read-only ref — no copy, no mutation
}

Prevention

  • Use ref return to return references to existing data (array elements, fields, etc.).
  • Use ref readonly return to avoid copying without allowing mutation.
  • Use ref return with ref local variables for in-place modification.
  • Ensure the ref return target outlives the method (no ref to local variables).
  • Use ref return for indexers on custom collections.
  • Use ref return in high-performance code where copying large structs is costly.

Common Mistakes with ref return

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

Can I return a reference to a local variable?

No. The compiler enforces ref-safe-to-escape rules. A ref return must point to memory that outlives the method call — fields, array elements, or ref parameters. Returning a ref to a local variable is a compile-time error.

What is ref readonly return?

public ref readonly T GetItem() returns a read-only reference. The caller cannot modify the value through the reference, but no copy is made. This is ideal for large structs in read-only scenarios — safe immutability with zero copying.

How do I store a ref return in a variable?

Declare the variable with ref: ref var item = ref GetMax(scores);. If you omit ref, the value is copied. Use ref readonly for read-only references: ref readonly var item = ref GetItem(0);.

Ref returns are used in DodaZIP's archive parser to provide direct access to compressed data without copying. For more C#, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro