Почему бокс встречается в интерполяционном выражении int? - PullRequest
0 голосов
/ 02 августа 2020

Например, такой код:

int n=1;
string str=$"{n}";

Но после явного добавления ToString() бокс не произойдет.

int n=1;
//The compiler will recommend removing the explicit call of the ToString() method
string str=$"{n.ToString()}";

В книге CLR via C# написано, что String.Format вызовет метод ToString изнутри, чтобы получить строковое представление объекта.

Поскольку метод ToString вызывается изнутри, почему в примере 1 происходит упаковка?

Ответы [ 3 ]

2 голосов
/ 02 августа 2020

Я отмечаю, что, несмотря на то, что ваш код использует интерполированную строку C#, он не использует класс FormattedString, поскольку компилятор C# будет использовать только FormattedString, если интерполированная строка непосредственно присваивается FormattedString -типированной переменной, полю или параметру (с чем я не согласен, но все равно).

CLR книги через C# пишет, что String.Format вызовет метод ToString внутренне, чтобы получить строковое представление объекта.

Да, но все перегрузки String.Format используют параметры типа Object или params Object[], что обязательно означает упаковку его аргументов.

почему бокс происходит в примере 1?

Потому что он должен передать int n в Object arg0.

Вот генерируемый IL когда я компилирую ваш первый блок кода в LinqPad (C# 8.0, с включенной оптимизацией компилятора):

IL_0000:  ldc.i4.1    
IL_0001:  stloc.0     
IL_0002:  ldstr       "{0}"
IL_0007:  ldloc.0     
IL_0008:  box         System.Int32
IL_000D:  call        System.String.Format
IL_0012:  pop         
IL_0013:  ret   

Вы можете увидеть инструкцию box при смещении инструкции IL_0008, прямо перед тем, как она пройдет это в String.Format.

1 голос
/ 02 августа 2020

«Звонок ToString» - это не магический c способ предотвратить бокс. Упаковка по-прежнему происходит, если вы вызывали ToString после , она была помещена в коробку, как в случае строковой интерполяции.

Как вы знаете, строковые интерполяции обычно обессахаривают вызовы string.Format. Если вы посмотрите на список доступных перегрузок , вы увидите, что нет перегрузки, которая принимает тип значения, например int или long. Каждая перегрузка требует object. Чтобы передать int в эти методы, его сначала нужно заключить в рамку. string.Format затем вызывает ToString в какой-то момент на object в штучной упаковке.

Сравните это с прямым вызовом ToString в строковой интерполяции. Преобразования в ссылочный тип (object) нет, поэтому нет бокса.

0 голосов
/ 02 августа 2020

Чтобы отформатировать строку, она может принимать только типы Object, к которым она вызывает ToString (), чтобы она могла ее объединить. Упаковка в основном превращает тип значения в ссылочный тип, что и происходит при неявном приведении к объекту, поэтому его можно сохранить в куче.

...