How to Resolve Error "CS0445: Cannot modify the result of an unboxing conversion" in C#
The Compiler Error CS0445 is a logical safety error related to Structs (Value Types) and Boxing. The message reads: "Cannot modify the result of an unboxing conversion".
In C#, when you store a Value Type (like a struct or int) inside a Reference Type variable (like object or an interface), it is called Boxing. When you cast it back to the struct type, it is called Unboxing.
Unboxing produces a temporary copy of the value. If you attempt to modify a field or property directly on that unboxed result in a single statement (e.g., ((Point)obj).X = 10;), you would be modifying the temporary copy, not the original object stored in the heap. The compiler prevents this because the change would be discarded immediately, creating a logic bug.
This guide explains how to correctly modify boxed value types.
Understanding Unboxing and Copies
- Reference Types: If you cast an object
(MyClass)obj, you get a reference to the same object. Modifying it updates the original. - Value Types (Unboxing): If you cast
(MyStruct)obj, the runtime extracts the value from the box and places a new copy on the stack.
If you write: ((MyStruct)obj).Value = 5;
- The runtime unboxes
objto a temp copy. - You set
Valueto 5 on the temp copy. - The statement ends. The temp copy is discarded.
objremains unchanged.
The compiler raises CS0445 to tell you: "You are trying to write to a temporary variable that vanishes instantly. This is surely not what you intended."
Scenario: Modifying a Casted Object
This error occurs frequently when using mutable structs (structs with public fields or setters) stored in generic object collections or loosely typed variables.
Example of error:
public struct Point
{
public int X;
public int Y;
}
public class Program
{
static void Main()
{
// 1. Box the struct into an object
object obj = new Point { X = 10, Y = 10 };
// ⛔️ Error CS0445: Cannot modify the result of an unboxing conversion
// (Point)obj creates a temporary Point. We try to set X on that temp.
((Point)obj).X = 20;
}
}
Solution 1: Unbox, Modify, Rebox (Standard Fix)
To modify the data, you must explicitly accept that you are working with copies.
- Unbox the data into a local variable.
- Modify the local variable.
- Assign the local variable back to the storage location (re-boxing it).
Solution:
public class Program
{
static void Main()
{
object obj = new Point { X = 10, Y = 10 };
// 1. Unbox to a local variable (This creates a copy on the stack)
Point p = (Point)obj;
// 2. Modify the local variable
p.X = 20;
// 3. Assign it back (Re-boxes the modified value)
obj = p;
// Verify the change
Console.WriteLine(((Point)obj).X);
}
}
Output:
20
This "Read-Modify-Write" pattern makes it explicit that the original box is being replaced by a new box containing the updated value.
Solution 2: Mutating via Interface (Advanced)
There is a subtle way to modify a boxed struct in-place without unboxing it fully to the stack: using an Interface.
When you cast a boxed struct to an interface it implements, you receive a reference to the boxed object on the heap, not a copy. Modifying the interface modifies the boxed value directly.
Mutable Structs Warning: This technique relies on Mutable Structs, which are generally considered a "bad practice" in C# design. However, if you are stuck with them, this works.
Solution:
// Define an interface for the mutation
public interface IPoint
{
int X { get; set; }
}
// Implement it in the struct
public struct Point : IPoint
{
public int X { get; set; }
public int Y { get; set; }
}
public class Program
{
static void Main()
{
object obj = new Point { X = 10, Y = 10 };
// ✅ Correct: Cast to the Interface.
// This returns a reference to the boxed object, not a copy.
((IPoint)obj).X = 20;
Console.WriteLine(((Point)obj).X);
}
}
Output:
20
Conclusion
CS0445 prevents "silent failures" where you modify a disposable copy of your data.
- Understand Structs: Remember that casting
(Struct)Objectcreates a copy. - Use Local Variables: Extract the struct to a variable
var temp = (Struct)obj;, modifytemp, and save it back. - Avoid Mutable Structs: If possible, design structs to be Immutable (
readonly). This forces you to overwrite the whole object anyway (obj = new Point(20, 10)), avoiding this confusion entirely.