Механізмів форматування рядків тексту (англ. string) у C#/.NET багато й різних: від простого зʼєднання обʼєктів і викликів перевизначеного методу object.ToString() аж до використання ICustomFormatter (у цій вправі він не розглядається).
Два найпоширеніші механізми форматування рядків тексту - це інтерполяція рядків та String.Format(). Клас StringBuilder (cross-ref-tba) теж можна використати, щоб побудувати рядок тексту, якщо є складнощі, наприклад кілька рядків.
ToString()
System.Object(), від якого успадковуються всі класи та структури, має метод ToString(). Наприклад, new DateTime(2019, 5, 23).ToString() відобразить «05/23/2019 00:00:00» (у потоці з культурою США - див. нижче). Є ситуації, як-от конкатенація рядків тексту, де цей типовий метод ToString() може викликатися неявно; "" + new DateTime(2019, 5, 23) дає той самий результат.
Крім типового методу ToString(), типи, для яких форматування має значення, мають перевантаження, що приймають рядок форматування або навіть постачальника формату. Зокрема, у BCL (Base Class Library, базовій бібліотеці класів) це числа, дати, переліки (enum) та GUID-и.
String.Format() приймає рядок тексту (у документації його називають складеним форматом), що складається з фіксованого тексту та заповнювачів (у документації їх називають елементами формату), і змінну кількість аргументів. Повернене значення обчислює кожен елемент формату за допомогою відповідного аргументу й поєднує обчислені значення з фіксованим текстом.
string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25))
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
Format() може бути кращим вибором, ніж інтерполяція, коли формат використовується в кількох виразах як своєрідний шаблон, або коли вбудувати і сам формат, і вирази, які треба відформатувати, надто громіздко, наприклад, коли йдеться про [дослівні рядки][verbatim-strings].
Технічно цей механізм називається складеним форматуванням.
Повніший список методів, що створюють рядки тексту й використовують складене форматування, наведено в цій статті.
Інтерпольовані рядки тексту починаються зі знака $ і містять вирази, які обчислюються під час виконання, у фігурних дужках. Елемент формату має такий синтаксис: $"{<interpolationExpression>[,<alignment>][:<formatString>]}". Вони позбавляють потреби в окремому списку аргументів. Результат функціонально еквівалентний механізму String.Format().
Вираз може містити будь-що з поточної області видимості. Вирівнювання - це довжина «поля», у якому розміщено текст. Якщо вирівнювання додатне, текст доповнюється пробілами зліва, а якщо відʼємне, то пробіли додаються справа від тексту.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
Текст у фігурних дужках (заповнювачі у випадку складеного формату та інтерпольовані вирази у випадку інтерполяції рядків) називається елементом формату.
Елемент формату може складатися щонайбільше з 3 частин. Перша частина - це обовʼязковий вираз або заповнювач аргументу, як у прикладі коду вище. Крім того, є необовʼязкове вирівнювання (вводиться комою «,») та необовʼязковий рядок форматування (вводиться двокрапкою «:»).
{<interpolationExpression>[,<alignment>][:<formatString>]}
Вирівнювання задає довжину «поля», у якому розміщується текст, з доповненням пробілами зліва, якщо вирівнювання додатне, або справа, якщо відʼємне.
Рядок форматування задає вигляд вихідного тексту: наприклад, чи додавати розділювачі тисяч для числа, чи виводити лише частину з датою обʼєкта DateTime.
Наступний код показує виведення частини з датою обʼєкта DateTime і числа з плаваючою комою в експоненційній формі.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
string.Format(
"I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
loadsOf, thatDay)
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
Існує як стандартне, так і власне форматування і для чисел, і для дат. Між власними та стандартними рядками немає принципової різниці, хіба що ми маємо змогу складати власні рядки форматування з символів формату. «власне» в цьому контексті не має нічого спільного з інтерфейсом ICustomFormatter, який використовується, коли ми розробляємо власні форматувальники.
Базова бібліотека класів (BCL) надає 2 форматувальники: DateTimeFormatInfo та NumberFormatInfo, і 6 груп рядків форматування.
Різні списки рядків форматування наведено нижче:
Рядки форматування Enum і GUID можна віднести до стандартних. Хоча enum і GUID мають перевантаження ToString(), які приймають IFormatProvider, неясно, чи це щось змінює.
У бібліотеці зроблено спробу надати рядкам форматування певної узгодженості (окрім того, що вони представлені як рядки тексту). Це прагнення до узгодженості видно в стандартних рядках. Насправді розробникові рідко доводиться зважати на різницю між стандартними та власними рядками. Хоча, якщо ми реалізуємо форматувальники для власних класів, добре було б наслідувати наявні стандартні рядки, коли наші класи цього потребують, загалом різницю можна сміливо ігнорувати.
Кожен потік виконання має типову культуру Thread.CurrentThread.CurrentCulture, інкапсульовану в примірнику CultureInfo. Культура потоку визначає, як типово форматуються дати й числа, з урахуванням регіональних відмінностей, як-от різниця у звичному форматі дати між Великою Британією DD/MM/YYYY та США MM/DD/YYYY.
CultureInfo реалізує інтерфейс IFormatProvider, який можна передати до певних перевантажень String.Format(). Це дозволяє перевизначити культуру потоку.