ToString() is it really cause boxing ?
More and more times I found myself arguing about ToString() as boxing. As you all know Tostring() is one of the object methods. Well, many programmers tend to believe that when they use ToSting() on value types (int, long, etc’) the CLR should box the value type into object to use the objects ToString(). That’s true if the value type uses the objects method. But, if value type override ToString() (and that’s what really happened) than boxing isn’t necessary since ToString() is part of the value type class.
The best way to demonstrate this behavior is by examines IL code. If boxing and unboxing is necessary we will find the box / unbox IL instructions. Take a look at this code which uses assignment of value type to object and backward, there for cause boxing/unboxing and using of Tostring() on value type.
int i = 9;
System.Collections.ArrayList oArr = new System.Collections.ArrayList();
//boxing
oArr.Add (i);
//unboxing
int iRet = (int)oArr[0];
//no boxing at all
string str = i.ToString();
The generated IL code that uses boxing/unboxing for using ArrayList with value types, as accepted. For using ToString() with value type you can see that IL uses int32 ToString() thus not using boxing.
.locals init ([0] int32 i,
[1] class [mscorlib]System.Collections.ArrayList oArr,
[2] int32 iRet,
[3] string str)
. . .
//000015: int i = 9;
IL_0006: ldc.i4.s 9
IL_0008: stloc.0
//000016: System.Collections.ArrayList oArr = new System.Collections.ArrayList();
IL_0009: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_000e: stloc.1
//000017: //boxing
//000018: oArr.Add (i);
IL_000f: ldloc.1
IL_0010: ldloc.0
IL_0011: box [mscorlib]System.Int32
IL_0016: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
IL_001b: pop
//000019: //unboxing
//000020: int iRet = (int)oArr[0];
IL_001c: ldloc.1
IL_001d: ldc.i4.0
IL_001e: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
IL_0023: unbox [mscorlib]System.Int32
IL_0028: ldind.i4
IL_0029: stloc.2
//000021:
//000022: //no boxing att all
//000023: string str = i.ToString();
IL_002a: ldloca.s i
IL_002c: call instance string [mscorlib]System.Int32::ToString()
IL_0031: stloc.3
//000024: }