I'm reading the book CLR via C# (4th edition), not as a newcomer to C# but as someone who knows the language trying to improve my grasp on the underlying functionality of the CLR.
Anyway, in this book an example is given (pg127-131) when discussing boxing/unboxing of value types which ends with a call to Console.WriteLine with a value type being concatenated to a string being passed as the argument.
The book explains that boxing and unboxing/copy operations cause overhead, which I already knew, but it then stated that the example could be optimized by running .ToString() on the value type being passed in.
I created an example program and compiled it, then used ILDASM to inspect the IL it generated. The version with ToString essentially is identical, but replaces the "box" instruction with a "call" to ToString (no shock there).
I benchmarked the code in a loop of 100000 runs, and there was no difference (it fluctuated which one was faster). I realize that other factors come into play when benchmarking (caches, etc.), but by the way the book explained it I had expected to see a significant difference when avoiding the "box" instruction even in a naieve benchmark..
Is it just that calling a function isn't much better? Is there a boxing operation going on in the ToString that nullifies the benefits and the book is wrong? Can someone shed some light on this?
For reference, here are the two ILDASM readouts:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 24 (0x18)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.4
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box [mscorlib]System.Int32
IL_0008: ldstr "."
IL_000d: call string [mscorlib]System.String::Concat(object,
object)
IL_0012: call void [mscorlib]System.Console::WriteLine(string)
IL_0017: ret
} // end of method Program::Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4.4
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call instance string [mscorlib]System.Int32::ToString()
IL_0009: ldstr "."
IL_000e: call string [mscorlib]System.String::Concat(string,
string)
IL_0013: call void [mscorlib]System.Console::WriteLine(string)
IL_0018: ret
} // end of method Program::Main