Должен ли я использовать .ToString () при объединении строковых и целочисленных переменных в C #?


19
int a = 1;
int b = 2;
int sum = a + b;
string expression = "Expression: " + a + " + " + b + " = " + sum;
Console.WriteLine(expression); //displays Expression 1 + 2 = 3

Должен ли я использовать:

string expression = "Expression: " + a + " + " + b + " = " + sum;

или

string expression = "Expression: " + a.ToString() + " + " + b.ToString() + " = " + result.ToString();

Рекомендуется ли использовать ToString()при объединении stringи int?


6
В a + "" + b + ""или "" + a + b + "", это не имеет значения: все это конкатенация строк. В a + b + ""этом имеет значение: aи bдобавляются первыми.
Тим С.

4
Примечание: в VB.NET этой неоднозначности можно избежать, если использовать явный оператор конкатенации строк : "Expression: " + aвызовет ошибку времени компиляции (с параметром Strict On), "Expression: " & aвыполнит конкатенацию строк.
Хайнци

Первый код приведет к боксу (int к Int32), второй - нет. Второй явно быстрее.
Случайные алфавиты

Ответы:


33

ToString использование

Нет, вы не должны использовать ToStringздесь.

Конкатенация строк автоматически преобразует не-строки в строки, что означает, что ваши два варианта почти идентичны:

Когда один или оба операнда имеют тип string, предопределенные операторы сложения объединяют строковое представление операндов.

Источник: C # Спецификация языка: оператор сложения, MSDN .

С другой стороны, первый (без ToString):

  • Короче, чтобы написать,
  • Короче читать,
  • Проще поддерживать и:
  • точно показывает намерение автора: объединить строки.

Поэтому предпочитаю первый.

Под капотом

Также интересно посмотреть, что происходит под капотом. Один из способов увидеть это - посмотреть IL-код в LINQPad. Эта программа:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = a + b;
    Console.WriteLine(c);
}

переводится на следующий IL:

IL_0001:  ldc.i4.3    
IL_0002:  stloc.0     // a
IL_0003:  ldstr       " Hello"
IL_0008:  stloc.1     // b
IL_0009:  ldloc.0     // a
IL_000A:  box         System.Int32
IL_000F:  ldloc.1     // b
IL_0010:  call        System.String.Concat
IL_0015:  stloc.2     // c
IL_0016:  ldloc.2     // c
IL_0017:  call        System.Console.WriteLine

Видишь это System.String.Concat? Это означает, что оригинальный код может быть написан так же, как и тот, который переводится в точно такой же IL:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = string.Concat(a, b); // This is the line which was changed.
    Console.WriteLine(c);
}

Когда вы читаете документациюstring.Concat(object[]) , вы можете узнать, что:

Метод объединяет каждый объект в аргументах , вызывая ToStringметод без параметров этого объекта; он не добавляет разделителей.

Это означает, что ToStringэто избыточно. Также:

String.Empty используется вместо любого нулевого объекта в массиве.

Что прекрасно подходит для случая, когда некоторые из операндов равны нулю (см. Сноску 1).

Хотя в последнем примере конкатенация была переведена в string.Concat, следует также выделить оптимизации компилятора:

var a = "Hello " + "World";

переводится на:

ldstr       "Hello World"
stloc.0

С другой стороны:

var a = string.Concat("Hello ", "World");

переводится на:

ldstr       "Hello "
ldstr       "World"
call        System.String.Concat
stloc.0

Другие альтернативы

Есть, конечно, и другие способы объединения строковых представлений объектов в C #.

  1. StringBuilderиспользуется, когда вам нужно выполнить много операций конкатенации, и помогает уменьшить количество создаваемых промежуточных строк. Решить, использовать ли вам StringBuilderобычную или обычную конкатенацию, может быть непросто. Используйте профилировщик или найдите соответствующие ответы в переполнении стека.

    Использование StringBuilderимеет существенный недостаток, заключающийся в затруднении чтения и обслуживания кода. Для простых случаев, как тот, что в вашем вопросе, StringBuilderэто не только вредно для читабельности кода, но и бесполезно с точки зрения производительности.

  2. string.Join следует использовать, когда вам нужно добавить разделители.

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

  3. string.Formatможет использоваться, когда шаблонирование строк предпочтительнее объединения строк. Один из случаев, когда вы можете предпочесть, это когда сообщение может быть локализовано, как это предлагается в ответе Кунтхет.

    Использование string.Formatимеет несколько недостатков, что делает его непригодным для простых случаев, таких как ваш:

    • При использовании простых заполнителей "{0}" часто неясно, какой параметр и куда идет. Часто ошибочно меняют параметры или забывают один. К счастью, C # 6 наконец вводит интерполяцию строк, которая решает эту проблему.

    • Производительность во время выполнения может ухудшиться. Конечно, не думайте, string.Formatчто всегда медленнее. Если производительность имеет значение, измерьте два подхода и определите, какой из них быстрее, основываясь на ваших реальных результатах, а не на предположениях.

    • Код немного длиннее для написания, длиннее для чтения и сложнее в обслуживании, хотя это крайне незначительно и не должно вас сильно беспокоить.


¹ Разница появляется, когда один из объектов null. Без ToString, а nullзаменяется пустой строкой. С ToString, NullReferenceExceptionброшено.


1
Именно по этой причине (непредсказуемое поведение) объединение строк с помощью +считается плохой практикой в ​​большинстве языков. В этом случае я бы использовал string.Concat, во многих случаях string.Formatлучше. Это, конечно, не Pythonic для использования +, и так как PEP 3101 %не рекомендуется в пользу str.format.
Арда Си

2
Подставляет ли пустая строка nullдействительно «красиво»? Ну, это не так плохо, как «по ошибке возобновить следующее» ...
Дедупликатор

Под капотом, если вы объединяете без вызова .ToString (), произойдет бокс ... и Concat(object[])будет использоваться вместо Concat(string[]). Так "string " + iчто на самом деле не идентичны"string " + i.ToString()
Случайные алфавиты

@RandomAlphabets: действительная точка. Тем не менее, разница заключается просто в расположении ToString(): кода OP в одном случае, System.String.Concatреализации в другом случае. Таким образом, ответ остается в силе: не пишите код, который не имеет никакой пользы.
Арсений Мурзенко

15

Вместо этого вы должны использовать форматирование строки. Проще отформатировать ваш номер в строковое представление или локализацию. например:

string expression = string.Format("Expression: {0} + {1} = {2}", a, b, sum);

Больше информации на MSDN .

Однако форматирование строк менее читабельно (и, возможно, также и производительность), чем конкатенация строк.


6
Хотите объяснить, почему этот вариант лучше?
Мировой инженер

@WorldEngineer: я обновил объяснение.
Кунет

12
Я не знаю обо всех остальных, но на самом деле я нахожу это более читабельным. Возможно, потому что я вырос на C, где s [n] printf - единственная реалистичная опция для такого рода кода.
Жюль

2
Но этот способ дает три источника ошибок вместо одного. Когда вы добавляете что-то в строку, вы 1) должны изменить строку формата, 2) не забыть добавить новый параметр в список, 3) попытаться выбрать правильное место в списке, где должен быть размещен новый параметр.
Руслан

2
Просто хочу присоединиться и сообщить вам о предстоящей функции интерполяции строк в C # 6. Вы напишите «Выражение: \ {a} + \ {b} = \ {sum}», чтобы получить тот же результат. codeproject.com/Articles/846566/…
cwap 14.12.14

-2

Если вы используете +конкатенацию, она сама использует String.Concatметод. Сама строка не представляет оператора +.

например:

int i = 10;
string str = "hello" + i;

составлен в:

int i = 10;
object o1 = "hello";
object o2 = i; // Note boxing
string str = string.Concat(o1, o2);

Если вы позвоните напрямую ToString, это позволит избежать бокса и вызвать Concat(string, string)перегрузку. Следовательно, ToStringвызов будет немного более эффективным, но недостаточно значительным. Вам лучше пойти с примером, который вы считаете более читабельным.


2
кажется, что это просто повторяет высказанные и объясненные в предыдущем ответе замечания : «Конкатенация строк автоматически преобразует не-строки в строки ...»
gnat
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.