Составное форматирование

В качестве входных данных для составного форматирования в .NET используется список объектов и строка составного формата. Строка составного формата состоит из фиксированного текста, пересекаемого с индексированных заполнителей, называемых элементами форматирования. Эти элементы формата соответствуют объектам в списке. Операция форматирования создает результирующую строку, состоящую из исходного фиксированного текста, в который включено строковое представление объектов из списка.

Внимание

Вместо использования составных строк форматирования можно использовать интерполированные строки , если язык и его версия поддерживают их. Интерполированная строка содержит интерполированные выражения. Каждое интерполированное выражение завершается значением выражения и включается в строку результатов, если строка назначена. Дополнительные сведения см. в разделе Интерполяция строк (справочник по C#) и Интерполированные строки (справочник по Visual Basic).

Следующие методы поддерживают функцию составного форматирования:

  • Метод String.Format, который возвращает отформатированную результирующую строку.
  • Метод StringBuilder.AppendFormat, который добавляет отформатированную результирующую строку в объект StringBuilder.
  • Некоторые перегруженные версии метода Console.WriteLine, которые отображают отформатированную результирующую строку в консоли.
  • Некоторые перегруженные версии метода TextWriter.WriteLine, которые записывают отформатированную результирующую строку в поток или файл. Классы, производные от TextWriter, например StreamWriter и HtmlTextWriter, также поддерживают эту функцию.
  • Метод Debug.WriteLine(String, Object[]), который выводит отформатированное сообщение в прослушиватели трассировки.
  • Методы Trace.TraceError(String, Object[]), Trace.TraceInformation(String, Object[]) и Trace.TraceWarning(String, Object[]), которые выводят отформатированные сообщения в прослушиватели трассировки.
  • Метод TraceSource.TraceInformation(String, Object[]), который записывает информационный метод в прослушиватели трассировки.

Строка составного формата

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

Рассмотрим следующий Format фрагмент кода:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Фиксированным текстом здесь является Name = и , hours = . Элементы {0}формата, индекс которых 0 соответствует объекту name, и {1:hh}индекс которого 1 соответствует объекту DateTime.Now.

Синтаксис форматирования элементов

Каждый элемент форматирования имеет следующий вид и состоит из следующих компонентов:

{index[,alignment][:formatString]}

Обязательны соответствующие фигурные скобки ({ и }).

Компонент индекса

Обязательный компонент индекса, который также называется описателями параметров, — это число, начиная с 0, которое определяет соответствующий элемент в списке объектов. То есть элемент формата, описатель параметров которого форматирует 0 первый объект в списке. Элемент формата, описатель параметров которого форматирует 1 второй объект в списке и т. д. В следующем примере содержатся четыре описателя параметров, нумерованные от нуля до трех, для представления простых чисел меньше 10:

string primes = string.Format("Four prime numbers: {0}, {1}, {2}, {3}",
                              2, 3, 5, 7);
Console.WriteLine(primes);

// The example displays the following output:
//      Four prime numbers: 2, 3, 5, 7
Dim primes As String = String.Format("Four prime numbers: {0}, {1}, {2}, {3}",
                                      2, 3, 5, 7)
Console.WriteLine(primes)

'The example displays the following output
'     Four prime numbers 2, 3, 5, 7

На один и тот же элемент в списке объектов может ссылаться сразу несколько элементов форматирования — достигается это путем задания одинакового описателя параметра. Например, можно отформатировать одно числовое значение в шестнадцатеричном, научном и числовом формате, указав строку составного формата, например "0x{0:X} {0:E} {0:N}"в следующем примере:

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Любой элемент форматирования может ссылаться на произвольный объект списка. Например, если есть три объекта, можно отформатировать второй, первый и третий объект, указав строку составного формата, например {1} {0} {2}. Объект, на который не ссылается элемент формата, игнорируется. Если описатель параметра ссылается на элемент за пределами списка объектов, то во время выполнения создается исключение FormatException.

Компонент выравнивания

Необязательный компонент alignment — это целое число со знаком, которое служит для указания желательной ширины поля форматирования. Если значение выравнивания меньше длины отформатируемой строки, выравнивание игнорируется, а длина форматируемой строки используется в качестве ширины поля. Форматируемые данные выравниваются в поле по правому краю, если alignment имеет положительное значение, или по левому краю, если alignment имеет отрицательное значение. При необходимости отформатированная строка дополняется пробелами. При использовании компонента alignment необходимо поставить запятую.

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

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Форматирование компонента строки

Необязательный компонент formatString — это строка формата, соответствующая типу отформатированного объекта. Можно указать:

  • Строка стандартного или настраиваемого числового формата, если соответствующий объект является числовым значением.
  • Стандартная или настраиваемая строка формата даты и времени, если соответствующий DateTime объект является объектом.
  • Строка формата перечисления, если соответствующий объект является значением перечисления.

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

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

Дополнительные сведения см. в IFormattable статьях и ICustomFormatter статьях интерфейса.

Тип или категория типов Смотрите
Типы даты и времени (DateTime, DateTimeOffset) Стандартные строки формата даты и времени

Настраиваемые строки формата даты и времени
Типы перечисления (все типы, производные от System.Enum) Enumeration Format Strings
Числовые типы (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Стандартные строки в числовом формате

Строки настраиваемых числовых форматов
Guid Guid.ToString(String)
TimeSpan Строки стандартного формата TimeSpan

Строки настраиваемого формата TimeSpan

Экранирование фигурных скобок

Начало и конец элемента форматирования обозначаются соответственно открывающей и закрывающей фигурной скобкой. Чтобы отобразить литеральную фигурную скобку или закрывающую фигурную скобку, необходимо использовать escape-последовательность. Укажите две открывающие фигурные скобки ({{) в фиксированном тексте, чтобы отобразить одну открывающую скобку ({) или две закрывающие фигурные скобки (}}), чтобы отобразить одну закрывающую скобку (}).

Экранированные фигурные скобки с элементом формата анализируются по-разному между .NET и платформа .NET Framework.

.NET

Фигурные скобки можно экранировать вокруг элемента формата. Например, рассмотрим элемент {{{0:D}}}формата, который предназначен для отображения открывающей фигурной скобки, числового значения, отформатированного в виде десятичного числа, и закрывающей фигурной скобки. Элемент формата интерпретируется следующим образом:

  1. Первые два открывающих скобки ({{) экранируются и дают одну открывающую скобку.
  2. Следующие три символа ({0:) интерпретируются как начало элемента формата.
  3. Следующий символ (D) интерпретируется как описатель стандартного числового формата десятичного стандарта.
  4. Следующая фигурная скобка (}) интерпретируется как конец элемента формата.
  5. Последние две закрывающие фигурные скобки экранируются и дают одну закрывающую фигурную скобку.
  6. Конечный результат, отображаемый, — литеральная строка {6324}.
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

.NET Framework

Фигурные скобки в элементе формата интерпретируются последовательно в порядке их обнаружения. Интерпретация вложенных фигурных скобок не поддерживается.

Порядок интерпретации скобок может привести к непредвиденным результатам. Например, рассмотрим элемент {{{0:D}}}формата, который предназначен для отображения открывающей фигурной скобки, числового значения, отформатированного в виде десятичного числа, и закрывающей фигурной скобки. Однако элемент формата интерпретируется следующим образом:

  1. Первые два открывающих скобки ({{) экранируются и дают одну открывающую скобку.
  2. Следующие три символа ({0:) интерпретируются как начало элемента формата.
  3. Следующий символ (D) будет интерпретирован как описатель десятичного стандартного числового формата, но следующие два экранированных фигурных скобки (}}) дают одну фигурную скобку. Так как результирующая строка (D}) не является стандартным числовым описателем, результирующая строка интерпретируется как настраиваемая строка форматирования, которая означает отображение литеральной строки D}.
  4. Последняя фигурная скобка (}) интерпретируется как конец элемента формата.
  5. Конечный результат, отображаемый, — литеральная строка {D}. Числовое значение, которое должно быть отформатировано, не отображается.
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

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

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

Порядок обработки

Если вызов метода составного форматирования включает IFormatProvider аргумент, значение которого не nullявляется, среда выполнения вызывает метод IFormatProvider.GetFormat для запроса ICustomFormatter реализации. Если метод может вернуть реализацию ICustomFormatter , он кэширован во время вызова метода составного форматирования.

Каждое значение в списке параметров, соответствующее элементу форматирования, преобразуется в строку следующим образом:

  1. Если форматируемое значение является значением null, возвращается пустая строка String.Empty.

  2. Если реализация ICustomFormatter доступна, среда выполнения вызывает ее метод Format. Среда выполнения передает значение элемента formatString формата (или null если оно отсутствует) методу. Среда выполнения также передает реализацию IFormatProvider методу. Если вызов метода ICustomFormatter.Format возвращается null, выполнение переходит к следующему шагу. В противном случае возвращается результат ICustomFormatter.Format вызова.

  3. Если значение реализует интерфейс IFormattable, вызывается метод ToString(String, IFormatProvider) этого интерфейса. Если он присутствует в элементе формата, значение formatString передается методу. null В противном случае передается. Аргумент IFormatProvider определяется следующим образом:

    • Для числового значения, если вызывается метод составного форматирования с аргументом IFormatProvider, не равным null, то среда выполнения запрашивает объект NumberFormatInfo из метода IFormatProvider.GetFormat. Если его не удается указать, если значение аргумента равно nullили если у метода составного форматирования нет IFormatProvider параметра, NumberFormatInfo используется объект для текущего языка и региональных параметров.

    • Для значения даты и времени, если вызывается метод составного форматирования с аргументом IFormatProvider, не равным null, то среда выполнения запрашивает объект DateTimeFormatInfo из метода IFormatProvider.GetFormat. В следующих ситуациях DateTimeFormatInfo вместо этого используется объект для текущего языка и региональных параметров:

    • Для объектов других типов, если метод составного форматирования вызывается с аргументом IFormatProvider, то его значение передается непосредственно в реализацию IFormattable.ToString. В противном случае null передается в реализацию IFormattable.ToString.

  4. Вызывается метод ToString без параметров, который переопределяет Object.ToString() или наследует поведение базового класса. В этом случае строка формата, указанная formatString компонентом в элементе форматирования, если она присутствует, игнорируется.

После выполнения предшествующих шагов производится выравнивание.

Примеры кода

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

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

Предположим, что сейчас май, а текущий день недели — четверг; тогда значение обеих строк для языка и региональных параметров "Английский (США)" в предыдущем примере будет равно Thursday May.

Метод Console.WriteLine предоставляет те же функциональные возможности, что и метод String.Format. Единственное различие между этими двумя методами состоит в том, что метод String.Format возвращает результаты в виде строки, а метод Console.WriteLine записывает результаты в поток вывода, связанный с объектом Console. В следующем примере метод используется Console.WriteLine для форматирования значения myNumber валюты:

int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

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

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

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

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

См. также