Reputation: 5764
This is more a 'wonder why' than a specific issue but look at the following code
static void Main(string[] args)
{
int val = 10;
Console.WriteLine("val is {0}", val); // (1)
Console.WriteLine("val is {0}", val.ToString()); //(2)
}
In case (1) the following IL is output
IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
IL_0004: ldstr "val is {0}"
IL_0009: ldloc.0
IL_000a: box [mscorlib]System.Int32
IL_000f: call void [mscorlib]System.Console::WriteLine(string,
object)
In case (2) where I explicitly call the toString method I get
IL_0014: nop
IL_0015: ldstr "val is {0}"
IL_001a: ldloca.s val
IL_001c: call instance string [mscorlib]System.Int32::ToString()
IL_0021: call void [mscorlib]System.Console::WriteLine(string,
object)
So in case (1), even though int overrides toString, the value type is boxed and the toString method is called which presumably then calls the vtable override
So the result is exactly the same but an explicit toString avoids a boxing operation
Anyone know why?
=Edit=
OK to be clear, what's confusing me is that I'm starting with the assumption that even though int derives from System.ValueType, that in turn derives from System.Object because it contains toString, GetHashCode etc.
So in my naive view ( probably from C++), if I override a method derived from System.Object then there is no need to cast to System.Object ( and hence box the value type ) because an overriden method exists and the compiler will automatically reference the vtable entry for the type.
I'm also assuming that calling Console.WriteLine() implicitly calls int.toString so perhaps that's where I'm going wrong. Hope that makes sense
OK - all sorted. Thanks all for setting me straight. All to do with a bad assumption of mine that Console.WriteLine was doing an implicit string conversion. Don't ask me why I thought that - seems blindingly obvious how wrong that is now :)
Upvotes: 15
Views: 3060
Reputation: 700562
You are not implicitly calling ToString
at all. The is no overload of the WriteLine
method that takes strings after the format string, it only takes objects.
So, you are not implicitly calling ToString
, you are implicitly converting the int
to object
. The first case is equivalent to:
Console.WriteLine("val is {0}", (object)val);
As the int
is a value type, boxing occurs.
The second case is equivalent to:
Console.WriteLine("val is {0}", (object)val.ToString());
As the string is a reference type, casting it to object doesn't actually cause any code to be emitted. It just matches the type with the method signature.
Upvotes: 15
Reputation: 755141
In the first call there is no .ToString call at all. Instead you are calling the function Console.WriteLine(object). The first parameter is of type int and must be boxed to satisfy the type object. Later on inside of WriteLite, .ToString will be called on the object.
Upvotes: 2
Reputation: 185663
Because in the first instance you're passing the int
as an object
in calling the Console.WriteLine()
function. This forces the int
to be boxed. In the second method you're invoking ToString
directly, which avoids boxing and passes a string
to WriteLine
, which is already a reference type.
Upvotes: 5