Difference between boxing a primitive type and boxing a custom str

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

I noticed some difference between boxing primitive type and boxing custom
struct. Can anyone please help to explain why?

Here are the codes:

struct MyStruct
{
public int c;

public MyStruct(int m)
{
c = m;
}
}

private void test()
{
// Testing primitive type
Int32 v = 5; // Create an unboxed value type variable
Object o = v; // o refers to the boxed version of v

v = 123; // Changes the unboxed value type to 123
Console.WriteLine(v); // Displays "123"

v = (Int32) o; // Unboxes o into v
Console.WriteLine(v); // Displays "5"


/////////////////////////////////////////////////////////////////////////////////////
//
Object o1 = o;
// Modifying the value of "o" in "Local" window does NOT affect value of
o1

/////////////////////////////////////////////////////////////////////////////////////

// Testing a custom struct
MyStruct s; // Create an unboxed value (struct) type variable
s.c = 10; // init the variable
Object os = s; // os refers to the boxed version of s

s.c = 100; // Change the unboxed value (struct) type to a different value
Console.WriteLine(s.c); // Display "100"

s = (MyStruct) os; // Unboxes os into s
Console.WriteLine(s.c); // Displays "10"


/////////////////////////////////////////////////////////////////////////////////////
Object os1 = os;
// Modifying the value of "os" in "Local" window DOES affect value of os1

/////////////////////////////////////////////////////////////////////////////////////
}

In my understanding, boxing will create a copy of for the value type on the
heap and returns the reference to it. In that case, then I will think
assigning the boxed item to another obejct variable will just create another
copy of the REFERENCE which will also point to the same copy of data on the
memory.

It seems to work as predicted for a custom struct I created. i.e., I set a
break point after:
Object os1 = os;
I can modify the value for os through the "local" windows during debug
session and I can see the value for os1 changed as well.

However, when I tried that with a primitive type (int), after calling
Object o1 = o;
and then modify the value for o in the "local" windows in debug session, the
value for o1 did NOT change. This suggests o1 is pointing to a separate copy.

Can anyone plese help to explain what I am missing here? Thanks.
 
David Shen said:
I noticed some difference between boxing primitive type and boxing custom
struct. Can anyone please help to explain why?

<snip>

This sounds like it's just a debugger quirk. I suspect it's not really
defined what happens when you change the value of o in the Locals
window - are you changing it to a reference to a new boxed value, or
changing the value of what's in the old box? It looks like it's doing
one thing for int (which it knows about, of course) and one thing for
the custom struct.

I'd be more worried if the difference showed up somehow in actual code.
 
David,
Object os = s; // os refers to the boxed version of s ....
Object os1 = os;
// Modifying the value of "os" in "Local" window DOES affect value of
os1
os1 refers to the same instance of the boxed structure.

If you change os.c you are changing a value within that boxed structure,
hence os1.c sees the same change.

This can be a good thing in that you can use
System.Reflection.PropertyInfo.SetValue to change a property of the boxed
structure. Or use System.Reflection.FieldInfo.SetValue to change a field of
the boxed structure.

BTW: VB.NET behaves as you expect, it calls
System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue when you
assign one object variable to another, or pass an object to a parameter, to
ensure the value of the variable is copied instead of the reference within
the variable. Which means if you want to modify a boxed structure you need
to call into C# to get the above reflection routines to work.

Both the C# & VB.NET way of doing it can be a good thing, depending on what
you expected result is.

Hope this helps
Jay
 
Jay,
Which means if you want to modify a boxed structure you need
to call into C# to get the above reflection routines to work.

You don't really have to do that. If you reference the boxed value
with a variable of type ValueType rather than Object, you get rid of
the GetObjectValue calls.



Mattias
 
Mattias,
Cool! that's handy to know.

Thanks
Jay

Mattias Sjögren said:
Jay,


You don't really have to do that. If you reference the boxed value
with a variable of type ValueType rather than Object, you get rid of
the GetObjectValue calls.



Mattias
 
Back
Top