Строковый вывод: формат или concat в С#?

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

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

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

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

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

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

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

Ответ 1

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

Это немного измененная версия вашего кода.
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 result = (p.FirstName + "" + p.LastName); взял: 166 мс - 595610 тиков

Ответ 2

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

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

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

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

Ответ 3

О, дорогая, прочитав один из других ответов, я попытался изменить порядок операций, поэтому сначала выполните конкатенацию, затем 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( "Старт!" ) до того, как первая операция вернет все время в строку.

Ответ 4

Строки неизменяемы, это означает, что один и тот же крошечный фрагмент памяти используется снова и снова в вашем коде. Добавление же двух строк вместе и создание одной и той же новой строки снова и снова не влияет на память..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

Ответ 5

Жаль, что плохие переводчики

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

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

Ответ 6

Вот мои результаты более 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");

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

Ответ 7

Конкатенация строк хорошо в простом сценарии - сложнее с чем-то более сложным, чем это, даже 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);

Ответ 8

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

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

Ответ 9

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

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

    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 мс, поэтому я также выводил тики таймера.

Ответ 10

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

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

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

Ответ 11

Для базовой конкатенации строк я обычно использую второй стиль - проще для чтения и проще. Однако, если я делаю более сложную комбинацию строк, я обычно выбираю 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 + ".");

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

Ответ 12

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

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

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

Ответ 13

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

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

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

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

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

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

Ответ 14

  • Форматирование - это способ ".NET". Некоторые инструменты рефакторинга (Refactor! For one) будут даже предлагать рефакторинг кода стиля concat для использования стиля форматирования.
  • Форматирование легче оптимизировать для компилятора (хотя второй, вероятно, будет реорганизован для быстрого использования метода Concat).
  • Форматирование обычно более понятное для чтения (особенно при форматировании "фантазии" ).
  • Форматирование означает неявные вызовы '.ToString' для всех переменных, что хорошо для читаемости.
  • В соответствии с "Эффективным С#" реализация .NET "WriteLine" и "Format" испорчена, они автоматически определяют все типы значений (что плохо). "Эффективный С#" советует явно выполнять вызовы ".ToString", которые IMHO являются фиктивными (см. публикация Jeff)
  • В настоящий момент подсказки типа форматирования не проверяются компилятором, что приводит к ошибкам во время выполнения. Однако это может быть изменено в будущих версиях.

Ответ 15

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

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

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

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

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

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

Ответ 16

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

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);

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

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

Ответ 17

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

Ответ 18

Через неделю 19 августа 2015 года этот вопрос будет ровно семь (7) лет. Теперь есть лучший способ сделать это. Лучше с точки зрения ремонтопригодности, поскольку я не выполнил ни одного теста производительности по сравнению с просто конкатенацией строк (но имеет ли значение в эти дни разница в несколько миллисекунд?). Новый способ сделать это с С# 6.0:

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

Эта новая функция лучше, IMO и на самом деле лучше в нашем случае, поскольку у нас есть коды, где мы создаем querystrings, значения которых зависят от некоторых факторов. Представьте себе один запрос, где у нас есть 6 аргументов. Поэтому вместо выполнения, например:

var qs = string.Format("q1={0}&q2={1}&q3={2}&q4={3}&q5={4}&q6={5}", 
    someVar, anotherVarWithLongName, var3, var4, var5, var6)

in может быть написано так, и его легче читать:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";

Ответ 19

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

  • Код должен выполняться миллионы раз
  • Вы делаете тонны конкатений (более 4 тонн).
  • Код предназначен для Compact Framework

В соответствии с хотя бы двумя из этих обстоятельств я бы вместо этого использовал StringBuilder.

Ответ 20

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

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

Ответ 21

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

Ответ 22

Приятный!

Просто добавлено

        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

Ответ 23

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

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 concats, '+' будет работать отлично для 1 concat. И если вы не заботитесь о оптимизации микропроизводительности, string.Format будет работать нормально в общем случае.

Заметка о культуре

И тогда там что-то называется культурой...

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

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

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

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

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

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

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

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

Это делает ваше решение базовым компромиссом между generalocate-and-append (-multiple) (w/w.o. culture) или просто назначает и добавляет.

Ответ 24

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

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

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

Ответ 25

Мне на самом деле нравится первая, потому что, когда есть много переменных, смешанных с текстом, мне кажется, что мне легче читать. Кроме того, проще использовать кавычки при использовании string.Format(), uh, format. Вот достойный анализ конкатенации строк.

Ответ 26

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

Ответ 27

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

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));

Ответ 28

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

Ответ 29

Мне было любопытно, где 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;
   }
}

Результаты:

Concat: 406 ticks
Concat: 356 ticks
Concat: 411 ticks
Concat: 299 ticks
Concat: 266 ticks
Format: 5269 ticks
Format: 954 ticks
Format: 1004 ticks
Format: 984 ticks
Format: 974 ticks
StringBuilder: 629 ticks
StringBuilder: 484 ticks
StringBuilder: 482 ticks
StringBuilder: 508 ticks
StringBuilder: 504 ticks

Ответ 30

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