Почему неявный вызов 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.