Skip to main content

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;

  1. The runtime unboxes obj to a temp copy.
  2. You set Value to 5 on the temp copy.
  3. The statement ends. The temp copy is discarded.
  4. obj remains 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.

  1. Unbox the data into a local variable.
  2. Modify the local variable.
  3. 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
note

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.

warning

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.

  1. Understand Structs: Remember that casting (Struct)Object creates a copy.
  2. Use Local Variables: Extract the struct to a variable var temp = (Struct)obj;, modify temp, and save it back.
  3. 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.