Сведения о вопросе

LiKIY

03:13, 14th August, 2020

Теги

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

Просмотров: 539   Ответов: 25

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

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

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

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

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

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

Я бы предпочел второй вариант.



  Сведения об ответе

ITSME

04:57, 23rd August, 2020

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

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

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

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


  Сведения об ответе

dump

06:07, 19th August, 2020

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

Это слегка измененная версия вашего кода.
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 результат = string.Format("{0} {1}", p.FirstName, p.LastName); взято: 618мс-2213706 тиков
1000000 x результат = (p.FirstName + "" + p.LastName); взято: 166мс-595610 тиков


  Сведения об ответе

PAGE

05:21, 13th August, 2020

О боже, - прочитав один из других ответов, я попытался изменить порядок операций, - так что сначала выполните конкатенацию, а затем 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

Таким образом, порядок операций имеет значение HUGE, или, скорее, самая первая операция является ALWAYS гораздо медленнее.

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

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.Writeline("Start!") до того, как первая операция вернет все времена в строй.


  Сведения об ответе

lats

09:04, 4th August, 2020

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

Попробуйте это на размер:

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


  Сведения об ответе

DINO

21:06, 1st October, 2020

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

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

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


  Сведения об ответе

park

19:34, 15th August, 2020

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

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


  Сведения об ответе

DINO

07:25, 28th August, 2020

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

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

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

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

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

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);


  Сведения об ответе

прога

13:37, 28th August, 2020

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

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


  Сведения об ответе

repe

13:31, 25th August, 2020

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

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

    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 раз медленнее!! Конкатенация даже не регистрировалась как 1ms, поэтому я также выводил тики таймера.


  Сведения об ответе

KOMP

12:10, 4th August, 2020

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

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

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


  Сведения об ответе

pumpa

14:05, 23rd August, 2020

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

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


  Сведения об ответе

park

16:44, 28th August, 2020

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

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

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


  Сведения об ответе

$DOLLAR

07:16, 20th August, 2020

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

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

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

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

В может быть написано вот так и это легче читать:

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


  Сведения об ответе

crush

10:19, 15th August, 2020

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

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

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

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

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

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


  Сведения об ответе

screen

21:06, 1st October, 2020

  1. Форматирование - это".NET " способ сделать это. Некоторые инструменты рефакторинга (Рефактор! например) даже предложит рефакторировать код в стиле конкат, чтобы использовать стиль форматирования.
  2. Форматирование проще оптимизировать для компилятора (хотя второй, вероятно, будет рефакторизован, чтобы использовать метод 'Concat', который является быстрым).
  3. Форматирование обычно понятнее для чтения (особенно с форматированием “fancy”).
  4. Форматирование означает неявные вызовы '.ToString' для всех переменных, что хорошо для удобства чтения.
  5. Согласно “эффективной C#”, реализации .NET 'WriteLine' и 'Format' перепутались, они автобокс всех типов значений (что плохо). "Эффективный C#” советует выполнять вызовы' .ToString ' явно, что IMHO является фиктивным (см. сообщение Джеффа )
  6. На данный момент подсказки типа форматирования не проверяются компилятором, что приводит к ошибкам во время выполнения. Однако это положение может быть изменено в будущих версиях.


  Сведения об ответе

DO__IT

01:12, 14th August, 2020

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

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

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

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

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

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


  Сведения об ответе

PHPH

23:45, 18th August, 2020

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

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

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

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

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

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

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

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

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

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

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


  Сведения об ответе

+-*/

08:39, 4th August, 2020

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


  Сведения об ответе

ЯЯ__4

21:06, 1st October, 2020

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

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

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


  Сведения об ответе

lesha

05:11, 12th August, 2020

Очень мило!

Просто добавить

        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


  Сведения об ответе

SSESION

21:06, 1st October, 2020

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

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


  Сведения об ответе

JUST___

00:39, 27th August, 2020

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


  Сведения об ответе

DO__IT

03:38, 24th August, 2020

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

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 значения, которые вы 'add' в строку. На разных машинах вы можете получить разные строки, если не используете string.Format с явным CultureInfo .

F.ex. подумайте, что произойдет, если вы измените a '.'for a ', ' во время написания вашего файла comma-seperated-values... в голландском языке десятичный разделитель-это запятая, поэтому ваш пользователь может просто получить сюрприз 'funny'.

Более детальный ответ

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

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

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

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

Это делает ваше решение основным компромиссом между overallocate-and-append (- кратным) (w/w.o. культура) или просто allocate-and-append.


  Сведения об ответе

pumpa

18:57, 12th August, 2020

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


  Сведения об ответе

+-*/

08:44, 22nd August, 2020

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться