Skip to main content

How to Resolve Error "CS0192: A readonly field cannot be used as a ref or out value" in C#

The Compiler Error CS0192 is an immutability protection error. The message reads: "A readonly field cannot be used as a ref or out value (except in a constructor)".

In C#, the readonly modifier allows a field to be assigned a value only during initialization or inside the constructor of the class. Once the constructor finishes, the field cannot be modified.

However, the keywords ref and out are used to pass arguments by reference, specifically allowing the called method to modify the variable passed in. Because passing a variable as ref or out implies that its value could change, the compiler forbids doing this with a readonly field to preserve the guarantee that the field will not change after initialization.

This guide explains the mechanics of this conflict and how to work around it safely.

Understanding the Immutability Conflict

  • readonly: Promises that the value effectively becomes a constant after the constructor runs.
  • ref / out: Gives a method the address of the variable so it can write a new value into it.

If you pass a readonly field to a method via ref, that method can write to that memory address. This breaks the readonly contract. Even if the method doesn't actually write to it, the compiler assumes it might and therefore blocks the call.

Scenario 1: Using out Parameters (e.g., Parsing)

This is a common scenario when trying to initialize or update a field based on parsing logic outside of the constructor.

Example of error: trying to parse a string directly into a readonly field using int.TryParse.

public class Configuration
{
public readonly int MaxRetries;

public void UpdateConfig(string input)
{
// ⛔️ Error CS0192: A readonly field cannot be used as an out value
// 'TryParse' requires write access to 'MaxRetries',
// but 'MaxRetries' is readonly.
int.TryParse(input, out MaxRetries);
}
}

Scenario 2: Using ref Parameters (e.g., Interlocked)

Thread-safe operations often use ref to modify a variable atomically. You cannot perform these atomic operations directly on a readonly field.

Example of error:

using System.Threading;

public class Counter
{
private readonly int _count;

public void Increment()
{
// ⛔️ Error CS0192: A readonly field cannot be used as a ref value
// Interlocked.Increment tries to write the new value back into _count.
Interlocked.Increment(ref _count);
}
}

Exception: Inside Constructors

As the error message states, the Constructor is the one place where readonly fields are mutable. Therefore, passing them as ref or out is valid if and only if the call happens inside the constructor.

public class Parser
{
public readonly int Value;

public Parser(string input)
{
// ✅ Correct: This is allowed because we are inside the constructor.
// The field is still "under construction".
int.TryParse(input, out Value);
}
}

Solution 1: Use a Local Variable (Copy Pattern)

If you are in a standard method (not a constructor), you cannot modify the readonly field. However, if you just want to use the logic of a method like TryParse, you can use a local variable.

For out parameters

Declare a local variable to receive the result. Note that you cannot assign this back to the readonly field (because it's read-only), but you can use the local variable for other logic.

public class Configuration
{
public readonly int MaxRetries = 5;

public void CheckInput(string input)
{
// ✅ Correct: Use a local variable to capture the output
if (int.TryParse(input, out int tempValue))
{
Console.WriteLine($"Parsed value: {tempValue}");
// Note: You still cannot do 'MaxRetries = tempValue;' here.
}
}
}

For ref parameters (Interlocked)

If you need to modify a value atomically, that value fundamentally cannot be readonly. See Solution 2.

Solution 2: Remove the readonly Modifier

If your design requires the field to be modified by ref or out methods outside of the constructor (e.g., an atomic counter, or a value that updates over time), then the field is not read-only by definition.

Solution: simply remove the keyword.

using System.Threading;

public class Counter
{
// ✅ Correct: Removed 'readonly'.
// This variable is intended to change over time.
private int _count;

public void Increment()
{
Interlocked.Increment(ref _count);
}
}
tip

Using in (C# 7.2+): If you are writing your own method and you want to pass a readonly struct by reference for performance (without modifying it), use the in modifier instead of ref. public void Process(in MyStruct s) { ... } allows passing readonly fields.

Conclusion

CS0192 enforces the integrity of your data.

  1. Check Context: Are you inside a constructor? If so, ref/out works.
  2. Check Intent:
    • If the field must change (e.g., via Interlocked), remove readonly.
    • If you just need to extract data (e.g., TryParse), use a local variable for the out parameter instead of the field.