tags:

views:

194

answers:

3

Hi 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 :)

+3  A: 

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.

Adam Robinson
But why not when int provides an explicit override so contains a vtable entry for the toString method?
zebrabox
@zebra: I'm not sure what you're asking. Again, the boxing operation takes place because the int must be referenced as an object. This doesn't happen in the second example because a string is being passed to WriteLine, not an int.
Adam Robinson
@Adam. It's OK, it all hinges on a bad assumption of mine that an implicit toString conversion was happening. Now I know that's not true it's all clear again. If Console.WriteLine accepts an object then the box must occur as Jared Par said to satisfy the method params
zebrabox
+1  A: 

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.

JaredPar
Yep. My bad. Stupid assumption of mine - all clear now. Cheers :)
zebrabox
+1  A: 

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.

Guffa
Yep, that's where I'm going wrong. I'm assuming there is an implicit cast occuring. Makes sense now!
zebrabox