Вывод строки: формат или конкат в C #?

Допустим, вы хотите вывести или объединить строки. Какой из следующих стилей вы предпочитаете?

  • var p = new { FirstName = "Bill", LastName = "Gates" };

  • Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

  • Console.WriteLine(p.FirstName + " " + p.LastName);

Вы предпочитаете использовать формат или просто соединяете строки? Что твое любимое? Один из них болит твои глаза?

Есть ли у вас рациональные аргументы, чтобы использовать один, а не другой?

Я бы пошел на второй.

19.08.2008 15:46:53
30 ОТВЕТОВ
РЕШЕНИЕ

Попробуйте этот код.

Это слегка измененная версия вашего кода.
1. Я удалил Console.WriteLine, поскольку он, вероятно, на несколько порядков медленнее, чем то, что я пытаюсь измерить.
2. Я запускаю секундомер перед циклом и останавливаю его сразу после этого, так что я не теряю точности, если для выполнения функции требуется, например, 26,4 такта.
3. То, как вы разделили результат на несколько итераций, было неверным. Посмотрите, что произойдет, если у вас есть 1000 миллисекунд и 100 миллисекунд. В обеих ситуациях вы получите 0 мс после деления на 1000000.

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

Вот мои результаты:

1000000 x result = string.Format ("{0} {1}", p.FirstName, p.LastName); потребовалось: 618мс - 2213706 тиков
1000000 x результат = (p.FirstName + "" + p.LastName); заняло: 166мс - 595610 тиков

88
1.03.2017 06:15:41
Очень интересно. Я получил в среднем 224 мс против 48 мс, улучшение х4,66, даже лучше, чем у вас х3,72. Интересно, есть ли инструмент посткомпиляции, который может переписать IL string.Format, который не использует какие-либо функции составного форматирования (то есть, просто {0}) и заменить их значительно более быстрой конкатенацией строк. Интересно, что такой подвиг достижим с существующим переписчиком IL, таким как PostSharp.
Allon Guralnek 29.09.2011 15:24:54
Строки являются неизменяемыми, это означает, что один и тот же крошечный фрагмент памяти используется снова и снова в вашем коде. Добавление тех же двух строк вместе и создание одной и той же новой строки снова и снова не влияет на память. .Net достаточно умен, чтобы использовать одну и ту же ссылку на память. Поэтому ваш код не проверяет разницу между двумя методами concat. Смотрите код в моем ответе ниже.
Ludington 13.11.2012 01:21:54
Честно говоря, я всегда объединяюсь, потому что мне легче читать, и это
puretppc 20.01.2014 02:09:06
Таким образом, скорость - единственная причина, чтобы выбрать один над другим?
niico 26.10.2016 22:58:52

Лично, второй, поскольку все, что вы используете, находится в прямом порядке, в котором он будет выводиться. Принимая во внимание, что с первым вы должны сопоставить {0} и {1} с правильным var, что легко испортить.

По крайней мере, это не так плохо, как в C ++ sprintf, где, если вы неправильно указали тип переменной, все это взорвется.

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

1
19.08.2008 15:49:57

Я думаю, что это сильно зависит от того, насколько сложным является выход. Я склонен выбирать тот сценарий, который работает лучше всего в то время.

Подберите правильный инструмент в зависимости от работы: D Какой из них выглядит чистым!

2
19.08.2008 15:50:34

Для очень простых манипуляций я бы использовал конкатенацию, но как только вы выйдете за 2 или 3 элемента, формат станет более подходящим IMO.

Еще одна причина, по которой предпочтение отдается String.Format, заключается в том, что строки .NET являются неизменяемыми, и при таком способе создается меньше временных / промежуточных копий.

7
19.08.2008 15:50:44

Я предпочитаю и второе, но у меня нет рациональных аргументов в поддержку этого положения.

2
19.08.2008 15:51:26

Обычно я предпочитаю первое, так как особенно, когда строки становятся длинными, их гораздо легче читать.

Другим преимуществом является, я полагаю, одно из показателей производительности, поскольку последний фактически выполняет 2 оператора создания строки перед передачей окончательной строки в метод Console.Write. Я полагаю, что String.Format использует StringBuilder под крышками, поэтому избегают множественных конкатенаций.

Однако следует отметить, что если параметры, которые вы передаете в String.Format (и другие такие методы, как Console.Write), являются типами значений, то перед передачей они будут помещены в коробку, что может привести к снижению производительности. Сообщение в блоге об этом здесь .

5
1.09.2009 11:31:12
Этот пост в блоге теперь находится по адресу: jeffbarnes.net/blog/post/2006/08/08/… . Я страдаю от недостатка репутации для редактирования.
Richard Slater 24.08.2009 12:34:38

Для базовой конкатенации строк я обычно использую второй стиль - легче читать и проще. Однако, если я делаю более сложную комбинацию строк, я обычно выбираю String.Format.

String.Format экономит много цитат и плюсов ...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

Сохранено только несколько символов, но я думаю, что в этом примере формат делает его намного чище.

5
19.08.2008 15:55:01

Конкатенация строк хороша в таком простом сценарии - она ​​сложнее с чем-либо более сложным, чем даже LastName, FirstName. С форматом, который вы можете сразу увидеть, какой будет окончательная структура строки при чтении кода, с конкатенацией становится почти невозможно сразу увидеть окончательный результат (за исключением очень простого примера, подобного этому).

В конечном итоге это означает, что, когда вы вернетесь, чтобы внести изменения в формат строки, у вас будет возможность всплыть и внести некоторые изменения в строку формата, или сморщить бровь и начать перемещаться по всем виды средств доступа к свойствам, смешанные с текстом, что более вероятно создает проблемы.

Если вы используете .NET 3.5, вы можете использовать метод расширения, подобный этому, и получить легкий переход от синтаксиса манжеты, например:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

Наконец, по мере усложнения вашего приложения вы можете решить, что для разумного сохранения строк в вашем приложении вы хотите переместить их в файл ресурсов для локализации или просто в статический помощник. Это будет НАМНОГО легче достичь, если вы постоянно используете форматы, и ваш код может быть просто реорганизован для использования чего-то вроде

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);
9
19.08.2008 15:56:23

На самом деле мне нравится первый, потому что, когда в тексте много переменных, мне кажется, что их легче читать. Кроме того, легче использовать кавычки при использовании строки. Формат () форматирования. Вот достойный анализ конкатенации строк.

1
19.08.2008 15:57:20
  1. Форматирование - это «.NET» способ сделать это. Некоторые инструменты рефакторинга (Refactor! For one) даже предлагают реорганизовать код в стиле concat для использования стиля форматирования.
  2. Форматирование легче оптимизировать для компилятора (хотя второе, вероятно, будет реорганизовано для использования быстрого метода Concat).
  3. Форматирование обычно более понятно для чтения (особенно при «причудливом» форматировании).
  4. Форматирование означает неявные вызовы '.ToString' для всех переменных, что хорошо для удобства чтения.
  5. Согласно «Эффективному C #», реализации .NET «WriteLine» и «Format» перепутаны, они автоматически блокируют все типы значений (что плохо). «Эффективный C #» советует явно выполнять вызовы «.ToString», которые, по моему мнению, являются поддельными (см. Публикацию Джеффа )
  6. На данный момент подсказки форматирования не проверяются компилятором, что приводит к ошибкам во время выполнения. Тем не менее, это может быть исправлено в будущих версиях.
4
19.08.2008 15:59:21

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

Используя следующий код:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

Я получил следующие результаты:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

Использование метода форматирования более чем в 100 раз медленнее! Конкатенация даже не регистрировалась как 1 мс, поэтому я также выводил тики таймера.

6
19.08.2008 16:02:27
Но, конечно, вы должны выполнить операцию более одного раза, чтобы получить измерения.
erikkallen 30.11.2009 21:10:47
И потерять вызов Console.Writeline (), поскольку это выходит за рамки вопроса?
Aidanapword 17.12.2010 11:41:01
ты тестировал со строителем строк? ;)
niico 26.10.2016 23:00:27

Я бы использовал String.Format, но у меня также была бы строка формата в файлах ресурсов, чтобы ее можно было локализовать для других языков. Использование простой строки concat не позволяет вам сделать это. Очевидно, что если вам никогда не понадобится локализовать эту строку, это не повод задуматься. Это действительно зависит от того, для чего предназначена строка.

Если это будет показано пользователю, я бы использовал String.Format, чтобы я мог локализовать, если мне нужно - и FxCop будет проверять его правописание, на всякий случай :)

Если он содержит числа или любые другие нестроковые объекты (например, даты), я бы использовал String.Format, потому что он дает мне больше контроля над форматированием .

Если это для создания запроса, такого как SQL, я бы использовал Linq .

Если бы для объединения строк внутри цикла я бы использовал StringBuilder, чтобы избежать проблем с производительностью.

Если это какой-то вывод, который пользователь не увидит и не повлияет на производительность, я бы использовал String.Format, потому что я все равно использую его, и я просто привык к нему :)

4
7.06.2009 19:27:14

Я всегда шел по маршруту string.Format (). Возможность сохранять форматы в переменных, как в примере Натана, является большим преимуществом. В некоторых случаях я могу добавить переменную, но как только объединяется более 1 переменной, я реорганизую использование форматирования.

1
19.08.2008 19:16:49

Да, и просто для полноты, следующее на несколько тиков быстрее обычной конкатенации:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
1
20.08.2008 08:38:11

О, дорогой - после прочтения одного из других ответов я попытался изменить порядок операций, поэтому сначала выполняю конкатенацию, а затем String.Format ...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

Таким образом, порядок операций имеет ОГРОМНОЕ различие, или, скорее, самая первая операция ВСЕГДА намного медленнее.

Вот результаты прогона, в котором операции выполняются более одного раза. Я пытался изменить порядок, но, как правило, все по тем же правилам, как только первый результат игнорируется:

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

Как вы можете видеть, последующие прогоны того же метода (я преобразовал код в 3 метода) пошагово быстрее. Наиболее быстрым представляется метод Console.WriteLine (String.Concat (...)), за которым следует обычная конкатенация и затем отформатированные операции.

Первоначальная задержка при запуске, вероятно, является инициализацией Console Stream, так как установка Console.Writeline («Start!») До того, как первая операция вернет все строки в соответствие.

54
11.07.2011 13:43:27
Затем полностью удалите Console.WriteLine из ваших тестов. Это искажает результаты!
CShark 26.05.2016 18:04:21

На самом деле, я вчера проводил эти тесты, но было уже поздно, поэтому я не ставил свои ответы.

Суть в том, что они в среднем занимают одно и то же время. Я сделал тест более 100000 итераций.

Я тоже попробую с StringBuilder и выложу код и результаты, когда вернусь домой.

0
20.08.2008 13:43:31

Вот мои результаты за 100 000 итераций:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

И вот код стенда:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

Итак, я не знаю, чей ответ пометить как ответ :)

14
9.08.2017 12:49:01
Почему фон для этого ответа синий?
user88637 7.06.2009 15:11:56
@yossi синее, потому что ответчик такой же, как и
Davy8 4.07.2009 20:45:18

Хороший!

Только что добавлен

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

И это даже быстрее (я думаю, что string.Concat вызывается в обоих примерах, но первый требует своего рода перевода).

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks
2
20.08.2008 18:07:42
Это занимает ровно столько же времени, поскольку компиляция строк на основе оператора переводится компилятором в вызовы string.Concat(...). Это делается во время компиляции, поэтому не влияет на производительность во время выполнения. Если вы запускаете тесты несколько раз или запускаете тестовые образцы большего размера, вы увидите, что они идентичны.
Allon Guralnek 29.09.2011 15:30:11

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

1
23.08.2008 19:55:24

Я поражен, что так много людей сразу хотят найти код, который выполняется быстрее всего. Если ОДИН МИЛЛИОН итераций ИСПОЛЬЗУЕТСЯ менее секунды для обработки, будет ли это в ЛЮБОМ СПОСОБЕ заметным для конечного пользователя? Не очень вероятно.

Преждевременная оптимизация = FAIL.

Я бы выбрал String.Formatвариант, только потому, что он имеет наибольшее значение с архитектурной точки зрения. Я не забочусь о производительности, пока она не станет проблемой (и если бы это произошло, я бы спросила себя: нужно ли мне объединять миллион имен одновременно? Конечно, они не все уместятся на экране ...)

Подумайте, хочет ли ваш клиент позже изменить его, чтобы он мог настроить, отображать "Firstname Lastname"или "Lastname, Firstname."с помощью параметра «Формат», это легко - просто поменяйте строку формата. С concat вам понадобится дополнительный код. Конечно, в этом конкретном примере это не имеет большого значения, но нужно экстраполировать.

157
29.08.2017 11:55:59
Хороший вопрос с точки зрения «преждевременной оптимизации == FAIL», да. Но когда вы начинаете платить за выполнение (облако и инфраструктура как услуга, кто-нибудь?) И / или вы начинаете поддерживать 1 миллион пользователей на что-то, то ответ на запрос одного пользователя не является вопросом. Стоимость обслуживания запроса для пользователя - это цена для вашей прибыли, а также проблема масштаба, если / когда поступают несколько других тысяч звонков ...
Aidanapword 17.12.2010 11:37:53
Это просто неправильно. В среде веб-разработки часто ваш код генерации строк будет глубоко в вашей модели, представлениях и контроллерах и может вызываться десятки тысяч раз за загрузку страницы. Сокращение времени, затрачиваемого на оценку кода генерации строк на 50%, может быть огромной победой.
Benjamin Sussman 29.07.2011 00:13:54
Подобный вопрос применим не только к одному экземпляру ОП. Ответ - это то, что люди могут вспомнить как «каким образом мне собирать струны?» как они пишут весь свой код.
Phil Miller 29.12.2012 17:47:37
@ Бенджамин: ... в этом случае, вы бы профилировать и найти это является вашим узким местом. Я бы поспорил на деньги, что вы просто тянете это из ниоткуда; написав и профилировав несколько веб-приложений в прошлом, я почти всегда находил узкое место во времени ответа (на стороне сервера) в запросах к базе данных.
BlueRaja - Danny Pflughoeft 2.07.2013 20:15:14
Это определенно НЕ преждевременная оптимизация. Совершенно ошибочно. Производительность строк может полностью затормозить пользовательский интерфейс, особенно в .NET, если вы много занимаетесь форматированием и сборкой строк. ubiquity.acm.org/article.cfm?id=1513451
user99999991 15.05.2015 21:53:00

Лучшим тестом было бы наблюдать за вашей памятью, используя Perfmon и счетчики памяти CLR. Насколько я понимаю, единственная причина, по которой вы хотите использовать String.Format вместо простой конкатенации строк, заключается в том, что поскольку строки являются неизменяемыми, вы без необходимости загружаете сборщик мусора временными строками, которые необходимо будет восстановить в следующем проходе.

StringBuilder и String.Format, хотя и потенциально медленнее, но более эффективны в использовании памяти.

Что плохого в конкатенации строк?

5
22.09.2008 14:27:23
Я согласен; каждая строковая операция создает новую копию строки. Вся эта память рано или поздно будет возвращена сборщиком мусора. Таким образом, выделение большого количества строк может вернуться к вам позже.
Marnix van Valen 13.05.2009 08:04:52

Если вы имеете дело с чем-то, что должно быть легко читаемым (а это большая часть кода), я бы остановился на версии перегрузки оператора UNLESS:

  • Код должен быть выполнен миллионы раз
  • Вы делаете тонны конкатов (более 4 - это тонна)
  • Код ориентирован на Компактную платформу

По крайней мере при двух из этих обстоятельств я бы вместо этого использовал StringBuilder.

3
22.09.2008 14:43:54

Мне было любопытно, где StringBuilder стоял с этими тестами. Результаты ниже ...

class Program {
   static void Main(string[] args) {

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

Полученные результаты:

Конкат: 406 тиков
Конкат: 356 тиков
Конкат: 411 тиков
Конкат: 299 тиков
Конкат: 266 тиков
Формат: 5269 тиков
Формат: 954 галочки
Формат: 1004 галочки
Формат: 984 галочки
Формат: 974 галочки
StringBuilder: 629 тиков
StringBuilder: 484 тика
StringBuilder: 482 тика
StringBuilder: 508 тиков
StringBuilder: 504 тика
1
22.09.2008 15:07:50

Я выбираю на основе читабельности. Я предпочитаю вариант форматирования, когда вокруг переменных есть текст. В этом примере:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

Вы понимаете значение даже без имен переменных, тогда как concat загроможден кавычками и знаками + и смущает мои глаза:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(Я позаимствовал пример Майка, потому что мне это нравится)

Если строка формата не имеет большого значения без имен переменных, я должен использовать concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

Опция форматирования позволяет мне прочитать имена переменных и сопоставить их с соответствующими номерами. Опция concat этого не требует. Меня все еще смущают кавычки и знаки +, но альтернатива еще хуже. Рубин?

   Console.WriteLine(p.FirstName + " " + p.LastName);

С точки зрения производительности, я ожидаю, что параметр format будет медленнее, чем concat, поскольку форматирование требует разбора строки . Я не помню, чтобы мне приходилось оптимизировать такого рода инструкции, но если бы я это сделал, я бы посмотрел на stringтакие методы, как Concat()и Join().

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

3
13.05.2009 08:35:59

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

3
7.06.2009 14:50:08

Согласно подготовительному материалу MCSD, Microsoft предлагает использовать оператор + при работе с очень небольшим числом конкатенаций (вероятно, от 2 до 4). Я до сих пор не уверен, почему, но это то, что нужно учитывать.

1
4.07.2009 20:31:04

Жаль бедных переводчиков

Если вы знаете, что ваше приложение останется на английском языке, тогда хорошо, сохраните отметки времени. Тем не менее, многие культуры обычно видят Фамилию Имя, например, по адресам.

Так что пользуйтесь string.Format(), особенно если вы когда-нибудь отправите свое приложение куда-нибудь, где английский не будет родным языком.

22
30.11.2009 21:11:53
Как string.Format()вести себя по-разному в разных культурах? Не будет ли по-прежнему печататься имя, затем фамилия? Похоже, что вам придется принимать во внимание различную культуру в обеих ситуациях. Я чувствую, что я что-то здесь упускаю.
Broots Waymb 9.12.2016 21:03:45
Я согласен с @DangerZone .. как бы string.Format()знать, что вы используете имя для адреса? Если string.Format()поменять местами {0} {1}на основе культуры, я бы посчитал это сломанным.
Alex McMillan 11.01.2017 21:43:47
Я полагаю, что Джереми пытался доказать, что в описанном сценарии поддержки разных стран может быть целесообразным извлечь саму строку формата в языковой ресурс. Для большинства стран этой строкой будет "{0} {1}", но для стран, где первая фамилия является типичной операцией (например, Венгрия, Гонконг, Камбоджа, Китай, Япония, Корея, Мадагаскар, Тайвань, Вьетнам и части Индии) эта строка будет "{1} {0}" вместо этого.
Richard J Foster 18.08.2017 13:38:30
В самом деле. Или, более тонко, добавьте строку формата в качестве атрибута человека. Я, например, хотел бы, чтобы моя фамилия была от моего имени, а мой коллега Бенг - нет.
Jeremy McGee 22.08.2017 09:49:05

Строки являются неизменяемыми, это означает, что один и тот же крошечный фрагмент памяти используется снова и снова в вашем коде. Добавление тех же двух строк вместе и создание одной и той же новой строки снова и снова не влияет на память. .Net достаточно умен, чтобы использовать одну и ту же ссылку на память. Поэтому ваш код не проверяет разницу между двумя методами concat.

Попробуйте это для размера:

Stopwatch s = new Stopwatch();

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0, sbElapsedMilliseconds = 0, sbElapsedTicks = 0;

Random random = new Random(DateTime.Now.Millisecond);

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (random.Next().ToString() + " " + random.Next().ToString());
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();

s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", random.Next().ToString(), random.Next().ToString());
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();

StringBuilder sb = new StringBuilder();
s.Start();
for(var i = 0; i < n; i++){
    sb.Clear();
    sb.Append(random.Next().ToString());
    sb.Append(" ");
    sb.Append(random.Next().ToString());
    result = sb.ToString();
}
s.Stop();
sbElapsedMilliseconds = s.ElapsedMilliseconds;
sbElapsedTicks = s.ElapsedTicks;
s.Reset();

Console.WriteLine(n.ToString() + " x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(\" \"); sb.Append(random.Next().ToString()); result = sb.ToString(); took: " + (sbElapsedMilliseconds) + "ms - " + (sbElapsedTicks) + " ticks");
Console.WriteLine("****************");
Console.WriteLine("Press Enter to Quit");
Console.ReadLine();

Пример вывода:

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 513ms - 1499816 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 393ms - 1150148 ticks
1000000 x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(" "); sb.Append(random.Next().ToString()); result = sb.ToString(); took: 405ms - 1185816 ticks
36
2.07.2013 20:04:46
В ответ
mikeschuld 2.07.2013 20:05:21
Я вижу, как использование string.Formatстоит крошечной производительности здесь. Архитектурно это лучше, так как это означает, что вы можете изменить формат более легко. Но струнный строитель я действительно не вижу смысла. Любой другой поток здесь говорит, что вы должны использовать Stringbuilder вместо объединения строк. В чем преимущество? Очевидно, не скорость, как доказывает этот тест.
roryok 27.07.2015 10:11:52

Поскольку я не думаю, что ответы здесь охватывают все, я хотел бы сделать небольшое дополнение здесь.

Console.WriteLine(string format, params object[] pars)звонки string.Format. «+» Подразумевает конкатенацию строк. Я не думаю, что это всегда связано со стилем; Я склонен смешивать два стиля в зависимости от контекста, в котором я нахожусь.

Короткий ответ

Решение, с которым вы сталкиваетесь, связано с распределением строк. Я постараюсь сделать это просто.

Скажи у тебя есть

string s = a + "foo" + b;

Если вы выполните это, он будет оцениваться следующим образом:

string tmp1 = a;
string tmp2 = "foo" 
string tmp3 = concat(tmp1, tmp2);
string tmp4 = b;
string s = concat(tmp3, tmp4);

tmpздесь на самом деле не локальная переменная, но она временная для JIT (она помещается в стек IL). Если вы помещаете строку в стек (например, ldstrв IL для литералов), вы помещаете ссылку на указатель строки в стеке.

В тот момент, когда вы вызываете concatэту ссылку, возникает проблема, потому что нет ни одной доступной строковой ссылки, содержащей обе строки. Это означает, что .NET необходимо выделить новый блок памяти, а затем заполнить его двумя строками. Причина, по которой это проблема, заключается в том, что распределение относительно дорого.

Что меняет вопрос на: Как вы можете уменьшить количество concatопераций?

Таким образом, грубый ответ: string.Formatдля> 1 конкатата '+' будет отлично работать для 1 конкатата. И если вам не нужны микропроцессорные оптимизации, string.Formatв общем случае все будет работать нормально.

Записка о культуре

А потом есть что-то под названием культура ...

string.Formatпозволяет использовать CultureInfoв вашем форматировании. Простой оператор «+» использует текущую культуру.

Это особенно важное замечание, если вы пишете форматы файлов и f.ex. doubleзначения, которые вы «добавляете» в строку. На разных машинах вы можете получить разные строки, если не используете string.Formatявные CultureInfo.

F.ex. подумайте, что произойдет, если вы измените «.» для ',' при написании файла значений, разделенных запятыми ... на голландском языке десятичный разделитель - запятая, так что ваш пользователь может просто получить «забавный» сюрприз.

Более подробный ответ

Если вы заранее не знаете точный размер строки, лучше использовать такую ​​политику, чтобы перераспределить используемые вами буферы. Сначала свободное место заполняется, после чего данные копируются в.

Увеличение означает выделение нового блока памяти и копирование старых данных в новый буфер. Старый блок памяти может быть освобожден. Вы получаете практический результат: выращивание - дорогостоящая операция.

Наиболее практичный способ сделать это - использовать политику перераспределения. Наиболее распространенной политикой является перераспределение буферов со степенями 2. Конечно, вы должны сделать это немного умнее (поскольку нет смысла расти с 1,2,4,8, если вы уже знаете, что вам нужно 128 символов). ) но вы получите картину. Политика гарантирует, что вам не нужно слишком много дорогих операций, которые я описал выше.

StringBuilderэто класс, который в основном перераспределяет основной буфер в степени двух. string.Formatиспользует StringBuilderпод капотом.

Это делает ваше решение основным компромиссом между overallocate-and-append (-multiple) (w / wo culture) или просто «распределить-и-добавить».

2
22.05.2015 09:19:03

Начиная с C # 6.0, для этого можно использовать интерполированные строки , что еще больше упрощает формат.

var name = "Bill";
var surname = "Gates";
MessageBox.Show($"Welcome to the show, {name} {surname}!");

Интерполированное строковое выражение выглядит как строка шаблона, содержащая выражения. Интерполированное строковое выражение создает строку, заменяя содержащиеся выражения на представления ToString результатов выражений.

Интерполированные строки имеют производительность, аналогичную String.Format, но улучшают читаемость и сокращают синтаксис из-за того, что значения и выражения вставляются в строку.

Пожалуйста, также обратитесь к этой статье dotnetperls по интерполяции строк.

Если вы ищете способ форматирования ваших строк по умолчанию, это имеет смысл с точки зрения читабельности и производительности (за исключением случаев, когда микросекунды будут иметь значение в вашем конкретном случае использования).

6
26.05.2016 18:07:13