What is the difference between two variable's ToString Calling ?
int i = 0;
i.ToString();
Does calling i.ToString() will make i first boxed then call ToString or i is already boxed before calling ToString() ?
int
is an alias of System.Int32
struct type (implicitly sealed) which has a method Int32.ToString()
and this is a method called in the second line of your code so no type conversion occurs.
System.Int32
is derived from System.ValueType
which is derived from System.Object
. Int32.ToString()
overrides ValueType.ToString()
which overrides Object.ToString()
.
The best way to check whether boxing occurs is to see IL code (I've been using ILSpy):
using System;
namespace BoxingTest
{
class Program
{
static void Main(string[] args)
{
int i = 0;
string s1 = i.ToString();
}
}
}
is translated to:
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 12 (0xc)
.maxstack 1
.entrypoint
.locals init (
[0] int32 i,
[1] string s1
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloca.s i
IL_0005: call instance string [mscorlib]System.Int32::ToString()
IL_000a: stloc.1
IL_000b: ret
} // end of method Program::Main
You can see that no boxing occurred and that System.Int32::ToString()
was called.
Boxing would have taken place if e.g. you casted your int
to object
explicitly or implicitly. (Note that conversion to object
type is not the only case when boxing happens)
Explicit casting to type object
:
using System;
namespace BoxingTest
{
class Program
{
static void Main(string[] args)
{
int i = 0;
string s2 = ((object)i).ToString();
}
}
}
gives:
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 16 (0x10)
.maxstack 1
.entrypoint
.locals init (
[0] int32 i,
[1] string s2
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: callvirt instance string [mscorlib]System.Object::ToString()
IL_000e: stloc.1
IL_000f: ret
} // end of method Program::Main
Boxing through implicit cast:
using System;
namespace BoxingTest
{
class Program
{
static void Main(string[] args)
{
int i = 0;
object o = i;
string s3 = o.ToString();
}
}
}
gives:
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 1
.entrypoint
.locals init (
[0] int32 i,
[1] object o,
[2] string s3
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: callvirt instance string [mscorlib]System.Object::ToString()
IL_0010: stloc.2
IL_0011: ret
} // end of method Program::Main
In all three cases strings will have value "0"
because Object.ToString()
knows the original type of the boxed variable and calls ToString()` of that type.
This is the IL code of the Object.ToString()
:
.method public hidebysig newslot virtual
instance string ToString () cil managed
{
.custom instance void __DynamicallyInvokableAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2052
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance class System.Type System.Object::GetType()
IL_0006: callvirt instance string System.Object::ToString()
IL_000b: ret
} // end of method Object::ToString
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