I was just participating in Stack Overflow question Is everything in .NET an object?.
And one poster (in comments of accepted answer) seemed to think that performing a method call on a value type resulted in boxing. He pointed me to Boxing and Unboxing (C# Programming Guide) which doesn't exactly specify the use case we're describing.
I'm not one to trust a single source, so I just wanted to get further feedback on the question. My intuition is that there is no boxing but my intuition does suck. :D
To further elaborate:
The example I used was:
int x = 5; string s = x.ToString(); // Boxing??
Boxing does not occur if the struct in question overrides the method inherited from the object as the accepted answer here states.
However if the struct doesn't override the method, a "constrain" CIL command is executed prior to a callvirt. According to the documentation, OpCodes.Constrained Field, this results in boxing:
If thisType is a value type and thisType does not implement method then ptr is dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction.
Boxing is used to store value types in the garbage-collected heap. Boxing is an implicit conversion of a value type to the type object or to any interface type implemented by this value type.
Boxing and unboxing are important concepts in C#. The C# Type System contains three data types: Value Types (int, char, etc), Reference Types (object) and Pointer Types. Basically, Boxing converts a Value Type variable into a Reference Type variable, and Unboxing achieves the vice-versa.
Boxing is implicit. In the above example, the integer variable i is assigned to object o . Since object type is a reference type and base class of all the classes in C#, an int can be assigned to an object type. This process of converting int to object is called boxing.
This shows that there is no boxing in the call i. ToString() , but there is boxing in the call i. GetType() .
Here's the IL for your code:
L_0001: ldc.i4.5 // get a 5 on the stack L_0002: stloc.0 // store into x L_0003: ldloca.s x // get the address of x on the stack L_0005: call instance string [mscorlib]System.Int32::ToString() // ToString L_000a: stloc.1 // store in s
So the answer in this case is no.
In the case you have given the answer is no, as plinth pointed out.
However, it will if you call a method through an interface pointer.
Consider the code:
interface IZot { int F(); } struct Zot : IZot { public int F() { return 123; } }
Then
Zot z = new Zot(); z.F();
Does not result in boxing:
.locals init ( [0] valuetype ConsoleApplication1.Zot z) L_0000: nop L_0001: ldloca.s z L_0003: initobj ConsoleApplication1.Zot L_0009: ldloca.s z L_000b: call instance int32 ConsoleApplication1.Zot::F() L_0010: pop L_0011: ret
However, this does:
IZot z = new Zot(); z.F(); .locals init ( [0] class ConsoleApplication1.IZot z, [1] valuetype ConsoleApplication1.Zot CS$0$0000) L_0000: nop L_0001: ldloca.s CS$0$0000 L_0003: initobj ConsoleApplication1.Zot L_0009: ldloc.1 L_000a: box ConsoleApplication1.Zot L_000f: stloc.0 L_0010: ldloc.0 L_0011: callvirt instance int32 ConsoleApplication1.IZot::F() L_0016: pop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With