О строковом форматировании в современном C++
Доброго времени суток! В этой статье я хотел бы рассказать о существующих возможностях строкового форматирования в современном C++, показать свои наработки, которые я уже несколько лет использую в реальных проектах, а также сравнить производительность различных подходов к строковому форматированию.
Строковое форматирование — это операция, позволяющая получить результирующую строку из строки-шаблона и набора аргументов. Строка-шаблон содержит текст, в который включены местозаполнители (placeholders), вместо которых подставляются аргументы.
Для наглядности небольшой пример:
Здесь:
Строка-шаблон: I have %d apples and %d oranges, so I have %d fruits
Местозаполнители: %d, %d, %d
Аргументы: apples, oranges, apples + oranges
При выполнении примера, получаем результирующую строку
Теперь посмотрим, что же нам предоставляет C++ для строкового форматирования.
Наследие C
Строковое форматирование в C осуществляется с помощью семейства функций Xprintf. С тем же успехом, мы можем воспользоваться этими функциями и в C++:
Это довольно неплохой способ форматирования, несмотря на кажущуюся неуклюжесть:
Но, конечно, не обошлось и без недостатков:
Функция std::to_string()
Начиная с C++11 в стандартной библиотеке появилась функция std::to_string(), которая позволяет преобразовать передаваемое значение в строку. Функция работает не со всеми типами аргументов, а только со следующими:
Класс std::stringstream
Класс std::stringstream — это основной способ строкового форматирования, который нам предоставляет C++:
Строго говоря, использование std::stringstream не является в полной мере строковым форматированием, так как вместо местозаполнителей мы вставляем в строку-шаблон аргументы. Это допустимо в простейших случаях, но в более сложных существенно ухудшает читаемость кода:
Объект std::sringstream позволяет реализовать несколько интересных оберток, которые могут понадобится в дальнейшем.
Преобразование «чего угодно» в строку:
Преобразование строки во «что угодно»:
Преобразование строки во «что угодно» с проверкой:
Также, можно написать пару оберток для удобного использования std::stringstream в одну строку.
Использование объекта std::stringstream для каждого аргумента:
Использование одного объекта std::stringstream для всей строки:
Забегая вперед, оказывается, что производительность std::to_string в 3-4 раза выше, чем у to_string, реализованной с помощью std::stringstream. Поэтому, логично будет использовать std::to_string для подходящих типов, а для всех остальных использовать шаблонную to_string:
Библиотека boost::format
Набор библиотек boost является мощным средством, отлично дополняющим средства языка C++ и стандартной библиотеки. Строковое форматирование представлено библиотекой boost::format.
Поддерживается указание как типовых местозаполнителей:
Единственный недостаток boost::format — низкая производительность, это самый медленный способ строкового форматирования. Также этот способ неприменим, если в проекте нельзя использовать сторонние библиотеки.
Итак, получается, что C++ и стандартная библиотека не предоставляют нам удобных средств строкового форматирования, поэтому будем писать что-то свое.
Обертка над vsnprintf
Попробуем написать обертку над Xprintf функцией, выделяя достаточно памяти и передавая произвольное количество параметров.
Для выделения памяти будем использовать следующую стратегию:
Для передачи параметров будем использовать механизм stdarg и функцию vsnprintf.
Шаблон с переменным количеством аргументов (Variadic Template)
В C++ начиная с C++11 появилась возможность использовать шаблоны с переменным количеством аргументов (Variadic Templates).
Такие шаблоны можно использовать при передаче аргументов в функцию форматирования. Также, нам больше не нужно заботиться о типах аргументов, так как мы можем использовать шаблонную to_string, которая была реализована ранее. Поэтому будем использовать порядковые местозаполнители.
Для получения всех аргументов отделяем первый аргумент, преобразуем его в строку, запоминаем и рекурсивно повторяем эту операцию. В случае отсутствия аргументов или при их окончании (конечная точка рекурсии) выполняем разбор строки-шаблона, подстановку аргументов и получаем результирующую строку.
Таким образом, у нас есть все, чтобы полностью реализовать функцию форматирования: парсинг строки-шаблона, сбор и преобразование в строку всех параметров, подстановку параметров в строку-шаблон и получение результирующей строки:
Алгоритм получился достаточно эффективным, работает за один проход по строке форматирования. В случае, если вместо местозаполнителя не удается вставить аргумент, он остается без изменений, исключений не генерируется.
Сравнение производительности
Сравнение производительности to_string и std::to_string, миллисекунд на миллион вызовов
| int, мс | long long, мс | double, мс | |
|---|---|---|---|
| to_string | 681 | 704 | 1109 |
| std::to_string | 130 | 201 | 291 |
Сравнение производительности функций форматирования, миллисекунд на миллион вызовов
| мс | |
|---|---|
| fstr | 1308 |
| sstr | 1243 |
| format | 788 |
| boost::format | 2554 |
| vtformat | 2022 |
Спасибо за внимание. Замечания и дополнения приветствуются.
Форматирование строк и ввода-вывода (современный C++)
Классы, функции и операторы C++ поддерживают форматированные строковые операции ввода-вывода. Например, в следующем коде показано, как задать cout Форматирование целого числа для вывода в шестнадцатеричном формате. Во-первых, он сохраняет текущее состояние, чтобы сбросить его, поскольку после передачи состояния формата cout оно остается таким образом, пока оно не изменится. Он не просто применяется к одной строке кода.
Этот подход является типобезопасным и расширяемым, но он также является сложным и подробным.
Альтернативные параметры формата
Некоторые преимущества Boost.Format :
Сейф: строго типизированный и вызывает исключение для ошибок, например спецификацию слишком мало или слишком много элементов.
Расширяемый: работает для любого типа, который может быть потоковым.
Удобно: стандартные POSIX и строки формата.
Хотя Boost.Format основана на средствах C++, которые являются надежными и расширяемыми, они не оптимизированы для производительности. При необходимости оптимизации производительности рассмотрите возможность использования функций printf и sprintf, которые быстро и просты в использовании. Однако они не являются расширяемыми и не защищены от уязвимостей. (Сейф версии существуют, но это существенно снижает производительность. Дополнительные сведения см. в разделе printf_s, _printf_s_l, wprintf_s, _wprintf_s_l и sprintf_s, _sprintf_s_l, swprintf_s, _swprintf_s_l).
В следующем коде показаны некоторые функции форматирования, повышающие эффективность.
Составное форматирование
Вместо использования строк составного формата можно использовать интерполированные строки, если их поддерживает язык и языковая версия, которые вы используете. Интерполированная строка — это строка, которая содержит интерполированные выражения. Каждое интерполированное выражение завершается значением выражения и включается в строку результатов, если строка назначена. Дополнительные сведения см. в разделе Интерполяция строк (справочник по C#) и Интерполированные строки (справочник по Visual Basic).
Возможность составного форматирования поддерживается следующими методами:
Метод String.Format, который возвращает отформатированную результирующую строку.
Метод StringBuilder.AppendFormat, который добавляет отформатированную результирующую строку в объект StringBuilder.
Некоторые перегруженные версии метода Console.WriteLine, которые отображают отформатированную результирующую строку в консоли.
Некоторые перегруженные версии метода TextWriter.WriteLine, которые записывают отформатированную результирующую строку в поток или файл. Классы, производные от TextWriter, например StreamWriter и HtmlTextWriter, также поддерживают эту функцию.
Метод Debug.WriteLine(String, Object[]), который выводит отформатированное сообщение в прослушиватели трассировки.
Метод TraceSource.TraceInformation(String, Object[]), который записывает информационный метод в прослушиватели трассировки.
Строка составного формата
Строка составного формата и список объектов используются в качестве аргументов методов, поддерживающих составное форматирование. Строка составного формата состоит из блоков фиксированного текста числом от нуля и больше, перемежаемых одним или несколькими элементами форматирования. Фиксированным текстом может являться произвольная строка, а каждый элемент форматирования должен соответствовать объекту или упакованной структуре из списка. В ходе составного форматирования создается новая результирующая строка, в которой все элементы форматирования заменены на строковое представление соответствующих объектов из списка.
Рассмотрим следующий фрагмент кода Format.
Синтаксис элементов форматирования
Каждый элемент форматирования имеет следующий вид и состоит из следующих компонентов:
Парные фигурные скобки («<" и ">«) здесь обязательны.
Индекс
Обязательный компонент index, также называемый описателем параметра, — это число, определяющее соответствующий объект из списка; индексация элементов ведется от нуля. Иными словами, элемент форматирования с индексом 0 отвечает за формат первого объекта в списке, элемент форматирования с индексом 1 служит для форматирования второго объекта в списке и т. д. В пример ниже входят четыре описателя параметров (с номерами от 0 до 3) для представления простых чисел меньше 10.
На один и тот же элемент в списке объектов может ссылаться сразу несколько элементов форматирования — достигается это путем задания одинакового описателя параметра. Например, одно и то же числовое значение можно отформатировать в шестнадцатеричном, экспоненциальном и десятичном виде путем задания следующей строки составного форматирования: «0x <0:X> <0:E><0:N>«, как показано в следующем примере.
Любой элемент форматирования может ссылаться на произвольный объект списка. Например, если имеется три объекта, то можно отформатировать сначала второй, а затем первый и третий объекты, указав следующую строку составного форматирования: » <1> <0><2>«. Объекты, на которые не ссылаются элементы форматирования, пропускаются. Если описатель параметра ссылается на элемент за пределами списка объектов, то во время выполнения создается исключение FormatException.
Выравнивание
Необязательный компонент alignment — это целое число со знаком, которое служит для указания желательной ширины поля форматирования. Если значение alignment меньше длины форматируемой строки, то alignment пропускается, и в качестве значения ширины поля используется длина форматируемой строки. Форматируемые данные выравниваются в поле по правому краю, если alignment имеет положительное значение, или по левому краю, если alignment имеет отрицательное значение. При необходимости отформатированная строка дополняется пробелами. При использовании компонента alignment необходимо поставить запятую.
В примере ниже определяются два массива: один содержит имена сотрудников, а второй — количество часов, которые они проработали в течение двух недель. Строка составного формата выравнивает имена по левому краю 20-символьного поля, а часы работы — по правому краю 5-символьного поля. Обратите внимание, что строка стандартного формата «N1» также используется для форматирования часов с одной цифрой дробной части.
Компонент строки формата
Необязательный компонент formatString — это строка формата, соответствующая типу форматируемого объекта. Если соответствующий объект является объектом DateTime, используется строка стандартного или настраиваемого формата чисел, а если соответствующий объект является значением перечисления, используется строка формата перечисления. Если компонент formatString не задан, то для числовых значений, значений даты и времени, а также перечислений используется общий формат («G»). При использовании компонента formatString необходимо двоеточие.
| Тип или категория типов | См. | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Типы даты и времени (DateTime, DateTimeOffset) | Строки стандартных форматов даты и времени Строки настраиваемых форматов даты и времени | ||||||||||||||||||||||||||||
| Типы перечисления (все типы, производные от System.Enum) | Строки форматов перечисления | ||||||||||||||||||||||||||||
| Числовые типы (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) | Строки стандартных числовых форматов Оформление фигурных скобокНачало и конец элемента форматирования обозначаются соответственно открывающей и закрывающей фигурной скобкой. Это означает, что для вывода открывающих и закрывающих фигурных скобок необходимо использовать escape-последовательности. Для вывода открывающей или закрывающей фигурной скобки в фиксированном тексте следует поставить две открывающие или, соответственно, закрывающие фигурные скобки подряд («<<" или ">>»). Фигурные скобки в элементе форматирования интерпретируются последовательно в порядке их обнаружения. Интерпретация вложенных скобок не поддерживается. Порядок интерпретации скобок может привести к непредвиденным результатам. Например, рассмотрим элемент форматирования «<<<<0:D>>>>», который должен вывести открывающую фигурную скобку, числовое значение, отформатированное в десятичном виде, и закрывающую фигурную скобку. В действительности элемент форматирования будет интерпретирован следующим образом: Следующий знак («D») должен интерпретироваться как указатель на десятичный числовой формат, но стоящая за ним пара фигурных скобок («>>») дает в результате одиночную фигурную скобку. Поскольку результирующая строка («D>») не является стандартным описателем числового формата, то она будет интерпретирована как строка пользовательского формата, что приведет к выводу строки «D>». Последняя фигурная скобка («>») интерпретируется как конец элемента форматирования. Итоговый результат, который будет выведен — строка « Одним из способов избежать неправильной интерпретации фигурных скобок и элементов форматирования при написании кода является раздельное форматирование фигурных скобок и элементов форматирования. Это означает, что первая операция форматирования должна выводить строку с открывающей фигурной скобкой, следующая операция — результат обработки элемента форматирования, а последняя операция — строку с закрывающей фигурной скобкой. Этот подход показан в приведенном ниже примере. Порядок обработкиКаждое значение в списке параметров, соответствующее элементу форматирования, преобразуется в строку следующим образом: Если значение реализует интерфейс IFormattable, вызывается метод ToString(String, IFormatProvider) этого интерфейса. Методу передается значение formatString (при его наличии в элементе форматирования) или значение null (в случае его отсутствия). Аргумент IFormatProvider определяется следующим образом: Для числового значения, если вызывается метод составного форматирования с аргументом IFormatProvider, не равным null, то среда выполнения запрашивает объект NumberFormatInfo из метода IFormatProvider.GetFormat. Если не удалось предоставить объект, если аргумент имеет значение null или метод составного форматирования не имеет параметра IFormatProvider, то используется объект NumberFormatInfo для языка и региональных параметров текущего потока. Для значения даты и времени, если вызывается метод составного форматирования с аргументом IFormatProvider, не равным null, то среда выполнения запрашивает объект DateTimeFormatInfo из метода IFormatProvider.GetFormat. Если не удалось предоставить объект, если аргумент имеет значение null или метод составного форматирования не имеет параметра IFormatProvider, то используется объект DateTimeFormatInfo для языка и региональных параметров текущего потока. Для объектов других типов, если метод составного форматирования вызывается с аргументом IFormatProvider, то его значение передается непосредственно в реализацию IFormattable.ToString. В противном случае null передается в реализацию IFormattable.ToString. Вызывается метод ToString без параметров, который переопределяет Object.ToString() или наследует поведение базового класса. В этом случае строка формата, указанная в компоненте formatString в элементе форматирования (при его наличии), игнорируется. После выполнения предшествующих шагов производится выравнивание. Примеры кодаПредположим, что сейчас май, а текущий день недели — четверг. Тогда значение обеих строк в предыдущем примере будет Thursday May для языка и региональных параметров «Английский (США)». В следующем примере демонстрируется форматирование нескольких объектов, в том числе форматирование одного и того же объекта двумя разными способами. В следующем примере показывается использование выравнивания при форматировании. Форматируемые аргументы разделены знаками вертикальной черты («|»), которые иллюстрируют выравнивание. Форматирование и интерполяция строк: stringformat в C#
Вывод на экран отформатированной строки для передачи информации — распространенная задача при разработке ПО. В C# StringFormat позволяет форматировать строки проще, быстрее и удобнее, чем при использовании конкатенации. Как этот метод работает, какие предоставляет возможности и какие есть способы форматирования — изучим в этой статье. Как форматировать строки в C# с помощью String.FormatМы уже рассказывали про базовые операции, которые позволяют работать со строками в C#. Здесь мы подробнее рассмотрим форматирование строк. Пример форматирования с помощью String.Format : Форматирование — это встраивание в строку различных элементов в заданном формате. Например, если нужно отобразить валюту, то мы подставляем к числу ее соответствующий символ — доллар, евро или другой. Если нужно показать проценты, то мы умножаем число на 100 и подставляем знак процента. Описатели форматовДля представления чисел в C# используются следующие описатели:
В таблице представлены лишь некоторые описатели. Подробную информацию по всем описателям и их свойствам смотрите в документации. Мы же здесь пройдёмся по примерам использования, чтобы вы могли попробовать форматирование на практике. String.Format также используется для преобразования даты и времени. С его помощью можно отобразить DateTime так, как вам хочется: сначала дату, сначала время, год в двузначном формате, год в четырехзначном формате. Таблица описателей формата даты и времени с подробными объяснениями и примерами также есть в документации. ВалютаДля форматирования валюты используется описатель “C” или “c”’. Знак валюты зависит от того, какая локаль установлена. Например, если это en-US, то в строке будет отображаться знак доллара, а если fr-FR, то знак евро. После описателя можно указать, сколько знаков требуется отобразить после запятой. Пример: Целые числаДля форматирования целых чисел используется описатель ‘D’ или ‘d’. Пример: После описателя можно явно указать, сколько символов должно отобразиться при выводе. Если в числе нет столько знаков, то в начале будут добавлены нули. Дробные числаДля форматирования дробных чисел используется описатели “E”, “F” или “G”: Подробнее о разнице между этими тремя описателями можно узнать из документации. Примеры: После описателя указывается, сколько знаков должно быть после разделителя (запятой в русской локали). Если количество знаков после запятой меньше, чем у числа, то число автоматически округляется в соответствии с правилами. ПроцентыДля форматирования процентов используется описатель ‘P’ или ‘p’. Пример: С помощью цифры после описателя можно управлять количеством знаком, которые будут отображаться в дробной части. Настраиваемые форматыC# предоставляет возможность настраивать формат вывода. Например, в качестве заместителя цифры используется символ #. С его помощью удобно представлять число как номер телефона: Настраиваемых числовых форматов тоже много. Например, знак “.” — это разделитель. С его помощью определяется разделитель целой и дробной частей в результирующей строке. Знак “%” — заместитель процента. Есть также настраиваемые форматы даты и времени. Полный список настраиваемых числовых форматов и форматов даты и времени с подробными объяснениями и примерами доступен в документации. Использование метода ToStringНапример, принимаем число, преобразуем его в строку и форматируем — по маске превращаем число в номер телефона: Принимаем число, используем описатель ‘C’, чтобы отобразить валюту, и указываем количество символов после запятой. Интерполяция строкИнтерполяция строк — упрощенный механизм форматирования строк. Он появился в версии C# 6.0. Простой пример: А вот пример с использованием настраиваемого формата: Можно выполнять математические операции прямо во время форматирования: И добавлять пространство до или после вывода: Как видите, возможностей для форматирования много, а пользоваться ими очень удобно. ЗаключениеC# предлагает разные способы для форматирования строк. Для самых простых случаев, когда достаточно просто соединить несколько строк вместе, достаточно использовать конкатенацию. Вместо метода String.Format можно использовать интерполированные строки. Их плюс — более удобный и понятный синтаксис. Видео для закрепления материала: Форматирование — это процесс преобразования экземпляра класса, структуры или значения перечисления в строковое представление. Результирующая строка затем демонстрируется пользователям или десериализуется для последующего восстановления значения с исходным типом данных. Преобразование может быть связано с рядом проблем: Внутреннее представление значений необязательно соответствует тому виду, в котором они должны быть представлены пользователям. Например, номер телефона может храниться в форме 8009999999, которая не отличается удобством для пользователей. Вместо этого номер должен отображаться в следующем виде: 800-999-9999. См. в подразделе Строки настраиваемого формата пример, в котором число форматируется таким образом. Для некоторых значений может потребоваться форматирование, учитывающее язык и региональные параметры. Например, в приложении, где числа используются для обозначения денежных сумм, числовые строки должны включать символ текущей валюты, разделители групп (в большинстве случаев они совпадают с разделителями тысяч) и символ-разделитель целой и дробной частей. Пример см. в разделе Форматирование с учетом языка и региональных параметров с помощью поставщиков формата. Переопределение метода Object.ToString, позволяющее определить настраиваемое строковое представление значения объекта. Дополнительные сведения см. ниже в разделе Переопределение метода ToString. Определение описателей формата, позволяющих использовать несколько видов строкового представления значения объекта. Например, описатель формата «X» в следующем операторе позволяет преобразовать целое число в шестнадцатеричное строковое представление. Использование поставщиков форматирования, позволяющих воспользоваться преимуществами соглашений о форматировании, присущих конкретному языку и региональным параметрам. Например, следующий оператор выводит значение валюты с использованием соглашений о форматировании языка и региональных параметров «en-US». Дополнительные сведения о форматировании с помощью поставщиков форматирования см. в разделе Поставщики форматирования. В следующих подразделах перечисленные методы преобразования объектов в их строковые представления рассматриваются более подробно. Форматирование по умолчанию при помощи метода ToStringСтруктуры наследуют от типа ValueType, который также является наследником Object. Хотя в ValueType метод Object.ToStringпереопределен, его реализация идентична базовой. Переопределение метода ToStringМетод ToString и строки форматаСтроки стандартного форматаСтрока стандартного формата содержит один описатель формата. Это алфавитный символ, определяющий строковое представление объекта, к которому он применяется. Также строка формата может содержать необязательный описатель точности, определяющий, сколько цифр отображается в результирующей строке. Если описатель точности не указан или не поддерживается, описатель стандартного формата будет эквивалентен строке стандартного формата. Сведения о строках форматов перечислений см. в разделе Enumeration Format Strings. Строки стандартного формата для числовых типов обычно задают результирующую строку, точный вид которой зависит от значения одного или нескольких свойств. Например, описатель формата «C» форматирует число в виде значения валюты. При вызове метода ToString со спецификатором формата «C» в качестве единственного параметра для определения строкового представления числового значения используются следующие свойства объекта NumberFormatInfo для текущего языка и региональных параметров: Свойство CurrencySymbol, определяющее символ валюты для текущего языка и региональных параметров. Положение символа валюты. Обозначение отрицательных значений: отрицательный знак в начале, отрицательный знак в конце или круглые скобки. Наличие пробела между числовым значением и символом валюты. Кроме того, строки числового формата могут содержать описатель точности. Смысл этого описателя зависит от строки формата, в которой он используется, но обычно он задает общее число цифр в результирующей строке или число цифр в дробной части. В следующем примере используется строка стандартного числового формата с описателем точности («X4»), что позволяет сформировать строковое значение из четырех шестидесятеричных цифр. Дополнительные сведения о строках стандартных числовых форматов см. в разделе Standard Numeric Format Strings. Дополнительные сведения о строках стандартных форматов даты и времени см. в разделе Строки стандартных форматов даты и времени. Строки стандартного формата также можно использовать для определения строкового представления прикладного объекта, формируемого с помощью метода ToString(String) такого объекта. Можно определить конкретные описатели стандартного формата, поддерживаемые объектом, а также решить, будут ли они зависеть от регистра символов. Реализация метода ToString(String) должна отвечать следующим условиям: Должен поддерживаться описатель формата, равный пустой ссылке ( Nothing в Visual Basic). Описатель формата, равный пустой ссылке, должен рассматриваться как эквивалент описателя формата «G». Например, во внутреннем представлении класса Temperature температура может храниться в градусах Цельсия, а для представления значения объекта Temperature в градусах Цельсия, Фаренгейта или Кельвина могут использоваться различные описатели формата. Ниже приведен пример. Строки настраиваемого форматаЕсли строка формата состоит из одного описателя настраиваемого формата, то перед ним должен стоять символ процента (%), чтобы его можно было отличить от описателя стандартного формата. В следующем примере описатель настраиваемого формата «М» используется для вывода одно- или двухзначного числа месяца для определенной даты. В следующем примере определяется строка настраиваемого формата, которая отображает значение Int64 как стандартный 7-значный американский номер телефона вместе с кодом города. Хотя строк стандартного формата обычно достаточно для выполнения большинства задач форматирования прикладных типов, для форматирования пользовательских типов также можно определять описатели настраиваемого формата. Все числовые типы (то есть типы Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64 и BigInteger), а также DateTime, DateTimeOffset, TimeSpan, Guid и все типы перечислений поддерживают форматирование с помощью строк форматов. Сведения о конкретных строках форматов, поддерживаемых каждым типом, см. в следующих разделах. Форматирование с учетом языка и региональных параметров с помощью поставщиков форматаИнтерфейс IFormatProvider включает один метод, GetFormat(Type), имеющий один параметр, задающий тип объекта, предоставляющего сведения о форматировании. Если метод может предоставить объект указанного типа, то он его возвращает. В противном случае метод возвратит пустую ссылку ( Nothing в Visual Basic).
.NET предоставляет следующие три класса, реализующие интерфейс IFormatProvider. DateTimeFormatInfo: класс, предоставляющий сведения о форматировании значений даты и времени для конкретного языка и региональных параметров. Реализация метода IFormatProvider.GetFormat в этом классе возвращает его экземпляр. NumberFormatInfo: класс, предоставляющий сведения о форматировании числовых значений для конкретного языка и региональных параметров. Реализация метода IFormatProvider.GetFormat в этом классе возвращает его экземпляр. Форматирование числовых значений, зависящее от языка и региональных параметровФорматирование значений даты и времени, зависящее от языка и региональных параметровИнтерфейс IFormattableРеализация интерфейса IFormattable в прикладных типах позволяет получить два преимущества: Составное форматированиеПомимо замены элементов форматирования строковыми представлениями соответствующего объекта, элементы форматирования также позволяют управлять перечисленными ниже аспектами. Вы можете указать конкретный способ представления объекта в виде строки, если объект реализует интерфейс IFormattable и поддерживает строки формата. Для этого после индекса элемента форматирования необходимо ввести : (двоеточие), а за ним — допустимую строку формата. В предыдущем примере для этого выполнялось форматирование значения даты с помощью строки формата «d» (шаблон короткого формата даты, например, <0:d>) и форматирование числового значения с помощью строки формата «C2» (например, <2:C2>для представления числа в виде значения валюты с двумя цифрами дробной части). Обратите внимание на то, что если присутствует и компонент выравнивания строки, и компонент строки формата, первый из них предшествует последнему (например, <0,-20:g>). Дополнительные сведения о составном форматировании см. в статье Составное форматирование. Настраиваемое форматирование с использованием интерфейса ICustomFormatter |