How to Resolve Error "CS0199: A static readonly field cannot be used as a ref or out value" in C#
The Compiler Error CS0199 is an immutability protection error. The message reads: "A static readonly field cannot be used as a ref or out value (except in a static constructor)".
In C#, ref and out parameters work by passing the memory address of a variable to a method, allowing that method to modify the variable's content directly. However, static readonly fields are designed to be immutable after initialization. Passing one by reference would allow a method to bypass the readonly safeguard and overwrite the value, violating the integrity of the field.
This guide explains why this restriction exists and how to work around it safely.
Understanding Immutability and References
static readonly: Ensures a field is assigned only once (during static initialization) and never changes thereafter.ref/out: explicitly grants a method permission to write new data into the variable's memory slot.
If the compiler allowed DoSomething(ref MyStaticReadonlyField), the method DoSomething could assign a new value to the field, breaking the promise that the field is "read-only." Therefore, C# forbids taking the address of a readonly field for modification purposes.
Scenario 1: Passing to ref Methods
This commonly happens when using utility methods (like Interlocked.Increment or custom swap functions) that require direct access to the variable.
Example of error:
public class Counter
{
// This field is meant to be immutable after init
public static readonly int MaxCount = 100;
public static void Update()
{
// ⛔️ Error CS0199: A static readonly field cannot be used as a ref or out value
// 'Process' might change the value of MaxCount, which is forbidden.
Process(ref MaxCount);
}
static void Process(ref int value)
{
value++; // This would violate 'readonly'
}
}
Scenario 2: Passing to out Methods
out is even stricter than ref; it requires the method to assign a value. Passing a readonly field to an out parameter is a guaranteed attempt to overwrite it.
Example of error:
public class Config
{
public static readonly int Id = 5;
public static void Reset()
{
// ⛔️ Error CS0199: 'GetNewId' MUST write to its parameter.
// Writing to 'Id' is illegal here.
GetNewId(out Id);
}
static void GetNewId(out int newId)
{
newId = 10;
}
}
Solution 1: Use a Local Variable (Copying)
If you need to pass the value of the readonly field to a method that takes ref, but you don't actually intend to change the global field (or you want to use the result locally), copy it to a temporary variable first.
Solution:
public class Counter
{
public static readonly int MaxCount = 100;
public static void Update()
{
// 1. Copy the value to a local variable
int tempCount = MaxCount;
// 2. Pass the local variable (which is mutable)
Process(ref tempCount);
// 3. Now 'tempCount' is 101, but 'MaxCount' remains 100.
System.Console.WriteLine($"Result: {tempCount}");
}
static void Process(ref int value)
{
value++;
}
}
This solution preserves the immutability of MaxCount. The external method modifies the copy, not the original static field.
Solution 2: Remove readonly (If Mutability is Required)
If your logic requires the method to update the static field (e.g., you are implementing a global counter that increments via Interlocked.Increment), then the field is not read-only by definition.
Solution: remove the readonly modifier.
using System.Threading;
public class GlobalState
{
// ✅ Correct: Removed 'readonly' because we intend to modify it.
public static int RequestCount = 0;
public static void RegisterRequest()
{
// 'ref' is now allowed because the field is mutable.
Interlocked.Increment(ref RequestCount);
}
}
Conclusion
CS0199 is a safeguard against accidental modification of protected data.
- Analyze Intent: Do you want the method to change the static field?
- Yes: The field shouldn't be
readonly. Remove the keyword. - No: You are likely using the wrong method, or you should pass a copy (local variable) instead of the field itself.
- Yes: The field shouldn't be
- Check Constructors: The only exception to this rule is inside the
staticconstructor of the same class, where the field is allowed to be initialized viareforout.