Question

lets say, i have the following code in c#

int x = 0;
x.ToString();

does this internally does a boxing of x? Is there a way to see this happening from visual studio?

Was it helpful?

Solution

In this specific case, you are using a System.Int32 (an int). That type redefines ToString, Equals and GetHashCode, so no boxing.

If you use a struct that doesn't redefine ToString what you'll have is a constrained callvirt to System.Object.ToString(). The definition of constrained:

When a callvirt method instruction has been prefixed by constrained thisType, the instruction is executed as follows:

  • If thisType is a value type and thisType implements method then ptr is passed unmodified as the 'this' pointer to a call method instruction, for the implementation of method by thisType.
  • 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.

So there isn't boxing if the value type implements ToString and there is boxing if it doesn't implement it... Interesting. I didn't know.

For non-virtual methods like GetType() that are defined in System.Object the value type is always boxed. Just tested with a:

5.GetType();

resulting IL code:

IL_0001: ldc.i4.5
IL_0002: box [mscorlib]System.Int32
IL_0007: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

OTHER TIPS

Here is the IL generated by your code:

IL_0001:  ldc.i4.0    
IL_0002:  stloc.0     // x
IL_0003:  ldloca.s    00 // x
IL_0005:  call        System.Int32.ToString

As you can see no boxing is taking place.

On the other hand, this code

object x = 0;
x.ToString();

will not surprisingly cause boxing:

IL_0001:  ldc.i4.0    
IL_0002:  box         System.Int32
IL_0007:  stloc.0     // x
IL_0008:  ldloc.0     // x
IL_0009:  callvirt    System.Object.ToString

Generally, if if the type of x is not int but any value type (struct) then you have to override ToString to avoid boxing. Specifically, a constrained callvirt is emited:

  • If thisType is a value type and thisType implements method then ptr is passed unmodified as the 'this' pointer to a call method instruction, for the implementation of method by thisType.

  • 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.

If you want to avoid boxing when calling Equals, GetHashCode and ToString on a value type you need to override these methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top