string.format зі змінними vs inline змінними


9

Які плюси та мінуси (якщо такі є) для використання

string output; 
int i = 10;
output = string.Format("the int is {0}", i);

проти

string output; 
int i = 10;
output = "the int is " + i;

Я завжди використовував останній приклад, але, схоже, велика частина інтернет-підручників використовує приклад string.format. Я не думаю, що є якісь реальні відмінності щодо ефективності, моя початкова думка - так, що кодеру не потрібно продовжувати ламати рядок, щоб вставити змінні.


8
Основна причина полягає в тому, що це робить переклад набагато простішим, оскільки вашій програмі не потрібно розуміти, як різні мови будують свої речення. Наприклад, багато виразів та фраз на французькій мові повертаються наперед, порівняно з їхніми англійськими перекладами.
JohnL

Відповіді:


22

Якщо ви вважаєте, що переклад є важливим у вашому проекті, перший синтаксис дійсно допоможе в цьому.

Наприклад, у вас можуть бути:

static final string output_en = "{0} is {1} years old.";
static final string output_fr = "{0} a {1} ans.";

int age = 10;
string name = "Henri";
System.out.println(string.Format(output_en, name, age));
System.out.println(string.Format(output_fr, name, age));

Також зауважте, що ваші змінні можуть не завжди знаходитись у тому самому місці речення з цим синтаксисом:

static final string output_yoda = "{1} years {0} has.";

4
+1 для використання Yoda-говорять як приклад синтаксису об'єкта-предмета-дієслова.
Майк Харріс

1
З C # у нас є новий варіант:System.out.println($"{name} is {age} year's old.");
Berin Loritsch


@BerinLoritsch: це, на жаль, абсолютно непридатно для локалізації.
Брайан Боттчер

@BryanBoettcher, зрозумів, але я нічого не бачив в ОП, що б це сказало.
Берін Лорич

8

Ознайомтеся з першою відповіддю для /programming/4671610/why-use-string-format . Він охоплює все, на мою думку, чому це краще.

Також у кожній .NET збірці є інтерн-пул, що містить колекцію унікальних рядків. Коли компілюється ваш код, до цього пулу додаються всі літеральні рядки, на які ви посилаєтесь у своєму коді. Якщо у вас є код, який виглядає приблизно так:

"the int is " + i + " and the double is " + d

Це робить його 2 струни в басейні.

Якщо у вас є:

"the int is {0} and the double is {1}"

У вас лише одна струна в басейні.

Це трохи складніше дізнатися , коли Струни інтерновані, і коли вони не тому , що компілятор має деякі розвідки при виявленні рядків , які можуть не повинні бути інтерновані іноді ... Перевірте, наприклад , в цю статтю , яка дає більше розуміння цього матерія.

Редагувати: трохи відкопавшись , я зіткнувся з цікавою відповіддю на питання, коли краще використовувати String.Format конкатенацію рядків? . Коротше кажучи, автор відповіді +30 голосів робить переконливий аргумент на користь конкатенації рядків, коли локалізація не задіяна.


2
Я також думаю, що стилістично це резонує з людьми, тобто людьми, такими як я, які використовуються для printf та sprintf з c.
Джонатан Хенсон,

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

4

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

Я впевнений, що першим способом є також користь від продуктивності через те, що не потрібно створювати зайві рядки; але це не моя головна турбота.


2

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


ах, я бачу, я думаю, я не придумав приклад: string.format ("int є {0}. знову це {0}", int);
Джим

1

Я думаю, що з string.Format()цим простіше зрозуміти, який саме результат буде (тому у вас немає проблем із забутими просторами чи чимось подібним), а також простіше вводити та змінювати.

Якщо ви хочете зробити дуже просте форматування, використовувати +оператор плюс може бути простіше, але я схильний використовувати його лише для об'єднання двох рядків, не більше.

Щоб показати, як string.Format()простіше змінити, врахуйте, що ви хотіли додати повну зупинку в кінці речення у своєму прикладі: перехід від string.Format("The int is {0}", i)до string.Format("The int is {0}.", i)- це лише один символ. Але перехід від "the int is " + iдо "the int is " + i + '.'набагато більше.

Ще однією перевагою string.Format()є те, що вона дозволяє легко вказати формат, який потрібно використовувати, наприклад string.Format("The int is 0x{0:X}.", i). Це ще важливіше при форматуванні дати.

Що стосується ефективності, string.Format()то, швидше за все, повільніше, ніж прості об'єднання рядків. Але такий код, швидше за все, не на гарячому шляху, тому це не має значення. І якщо це станеться, вам, ймовірно, краще користуватися StringBuilder.


string.Format все одно використовує StringBuilder
Bryan Boettcher

1

Використовуйте той, який робить ваш код найбільш читабельним. Не турбуйтеся про продуктивність.

Для вашого прикладу нижче я віддаю перевагу B, оскільки він просто читабельніший. Але мовні переклади вище також мають сенс. Не дозволяйте нікому змушувати вас використовувати string.Format, натомість читайте та вказуйте на чудовий блог Джеффа Етвудса на тему "Сумна трагедія мікрооптимізацій "

A:

string output; 
int i = 10;
output = string.Format("the int is {0}", i);

проти

B:

string output; 
int i = 10;
output = "the int is " + i;

-1

Ref: String output: формат або concat у C #?

Розглянемо цей код.

Це трохи модифікована версія вашого коду.

  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); took: 618ms - 2213706 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 166ms - 595610 ticks

1
Як це відповідає аспектам, якщо перший приклад коду чи другий приклад коду є кращим дизайном? Як пояснюється півтора секунди за 1М ітерацій, якщо це простіший код для обслуговування або ні?

Джим запитав: "Які плюси і мінуси?" Це показує, що на протязі багатьох ітерацій String.Format швидше.
jp2code

Ви повинні розглянути можливість додати це до своєї відповіді, а не залишати її як блок коду та відмінності від коду ОП. На даний момент ваша відповідь не відповідає на питання ОП англійською мовою. Подивіться на інші відповіді. Можна було б видалити з них весь код і все ж мати відповідь на питання ОП.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.