Почему неявный вызов toString по типу значения вызывает инструкцию окна

Это больше "интересно, почему", чем конкретная проблема, но посмотрите на следующий код

        static void Main(string[] args)
        {
            int val = 10;

            Console.WriteLine("val is {0}", val); // (1)
            Console.WriteLine("val is {0}", val.ToString()); //(2)


        }

В случае (1) выводится следующий IL

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)

В случае (2), когда я явно вызываю метод toString, я получаю

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)

Итак, в случае (1), хотя int переопределяет toString, тип значения помещается в бокс и вызывается метод toString, который предположительно затем вызывает переопределение vtable

Таким образом, результат будет точно таким же, но явный toString избегает операции бокса

Кто-нибудь знает, почему?

= Edit =
ОК, чтобы быть ясным, что меня смущает, что я начинаю с предположения, что хотя int происходит из System.ValueType, который, в свою очередь, происходит из System.Object, потому что он содержит toString, GetHashCode и т.д.
Таким образом, в моем наивном представлении (возможно, из С++), если я переопределяю метод, полученный из System.Object, тогда нет необходимости бросать в System.Object(и, следовательно, вводить тип значения), потому что существует метод overriden, и компилятор будет автоматически укажите запись vtable для типа.
Я также предполагаю, что вызов Console.WriteLine() неявно вызывает int.toString, поэтому, возможно, там, где я ошибаюсь. Надеюсь, что имеет смысл

ОК - все отсортировано. Спасибо всем за то, что вы меня прямо посадили. Все, что я сделал с плохим предположением о том, что Console.WriteLine выполнял неявное преобразование строк. Не спрашивайте меня, почему я думал, что это кажется ослепительно очевидным, как это неправильно сейчас:)

Ответ 1

Вы вообще не вызываете ToString. Это не перегрузка метода WriteLine, который берет строки после строки формата, он принимает только объекты.

Итак, вы неявно вызываете ToString, вы неявно конвертируете int в object. Первый случай эквивалентен:

Console.WriteLine("val is {0}", (object)val);

Поскольку int - тип значения, происходит бокс.

Второй случай эквивалентен:

Console.WriteLine("val is {0}", (object)val.ToString());

Поскольку строка является ссылочным типом, приведение ее в объект фактически не вызывает выброса какого-либо кода. Он просто соответствует типу с сигнатурой метода.

Ответ 2

Потому что в первом случае вы передаете int как object при вызове функции Console.WriteLine(). Это заставляет int быть в коробке. Во втором методе вы вызываете ToString напрямую, что позволяет избежать бокса и передает string в WriteLine, который уже является ссылочным типом.

Ответ 3

В первом вызове нет вызова .ToString. Вместо этого вы вызываете функцию Console.WriteLine(объект). Первый параметр имеет тип int и должен быть помещен в бокс для удовлетворения объекта типа. Позже внутри WriteLite на объект будет вызываться .ToString.