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?
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?
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()
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.
© 2022 - 2024 — McMap. All rights reserved.
ToString
implementation onint
will return the string representation of theint
, which is more a conversion. No casting or boxing is in sight in this instance. As Daniel asks, why do you want to know this? Is there an underlying issue? – DulcieGetType()
, because it isn't overridden in value types and is defined only inSystem.Object
. – Gimmalstruct
is a value type... unless I'm missing your point? – DulcieGetType
on anint
boxes the int. But why would you callGetType
on an unboxedint
? You already know what type it is. Just saytypeof(int)
if you need that type object. (If you are calling it on a boxedint
then obviously there is no boxing penalty because it's already boxed by assumption.) – UnmeaningT : struct
, but even then it's useless, andGetType()
is the only relevant non-virtual method ofSystem.Object
, because the others are protected or virtual or special or static. – Gimmaltypeof(T)
in the generic case and you'll get the type object for the type argument, not the type parameter. Moreover, it is dangerous to sayt.GetType()
fort
of typeT
(this time assuming no constraint) becauseT
could beint?
andt
could benull
, in which case you boxt
tonull
reference and then dereference it to callGetType()
, crashing. – UnmeaningT
isint?
andt
is notnull
then you boxt
toint
andGetType()
returns theint
type, not theint?
type, which is probably unexpected. – Unmeaning