Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does calling a method on a value type result in boxing in .NET?

Tags:

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.

like image 971
Quibblesome Avatar asked Jan 12 '09 18:01

Quibblesome


People also ask

Where does .NET store boxed value-types?

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.

What is boxing unboxing C#?

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.

Which of the following is implicit boxing?

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.

Is ToString a boxing?

This shows that there is no boxing in the call i. ToString() , but there is boxing in the call i. GetType() .


2 Answers

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.

like image 183
plinth Avatar answered Sep 24 '22 00:09

plinth


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  
like image 34
Rob Walker Avatar answered Sep 20 '22 00:09

Rob Walker