Метод System.String.Format

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

Внимание

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

Примеры

В этой статье перемежаются многочисленные примеры, вызывающие Format метод. Вы также можете скачать полный набор примеров String.Format , включаемых в проект .NET Core для C#.

Ниже приведены некоторые примеры, включенные в статью:

Создание строки формата

Вставка строки
Элемент формата
Форматирование элементов с одинаковым индексом

Форматированные выходные данные элемента управления

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

Учет языка и региональных параметров форматирования

Учет языка и региональных параметров форматирования

Настройка операции форматирования

Настраиваемая операция форматирования
Поставщик перехвата и римский числовый формататор

Начало работы с методом String.Format

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

Decimal pricePerOunce = 17.36m;
String s = String.Format("The current price is {0} per ounce.",
                         pricePerOunce);
Console.WriteLine(s);
// Result: The current price is 17.36 per ounce.
let pricePerOunce = 17.36m
String.Format("The current price is {0} per ounce.", pricePerOunce)
|> printfn "%s"
// Result: The current price is 17.36 per ounce.
Dim pricePerOunce As Decimal = 17.36D
Dim s As String = String.Format("The current price is {0} per ounce.",
                              pricePerOunce)
' Result: The current price is 17.36 per ounce.

И вы можете управлять форматированием этого значения:

Decimal pricePerOunce = 17.36m;
String s = String.Format("The current price is {0:C2} per ounce.",
                         pricePerOunce);
Console.WriteLine(s);
// Result if current culture is en-US:
//      The current price is $17.36 per ounce.
let pricePerOunce = 17.36m
String.Format("The current price is {0:C2} per ounce.", pricePerOunce)
|> printfn "%s"
// Result if current culture is en-US:
//      The current price is $17.36 per ounce.
Dim pricePerOunce As Decimal = 17.36D
Dim s As String = String.Format("The current price is {0:C2} per ounce.",
                              pricePerOunce)
' Result if current culture is en-US:
'      The current price is $17.36 per ounce.

Помимо форматирования, можно также управлять выравниванием и интервалом.

Вставка строки

String.Format начинается со строки форматирования, за которой следует один или несколько объектов или выражений, которые будут преобразованы в строки и вставлены в указанное место в строке форматирования. Например:

decimal temp = 20.4m;
string s = String.Format("The temperature is {0}°C.", temp);
Console.WriteLine(s);
// Displays 'The temperature is 20.4°C.'
let temp = 20.4m
String.Format("The temperature is {0}°C.", temp)
|> printfn "%s"
// Displays 'The temperature is 20.4°C.'
Dim temp As Decimal = 20.4D
Dim s As String = String.Format("The temperature is {0}°C.", temp)
Console.WriteLine(s)
' Displays 'The temperature is 20.4°C.'

Строка {0} форматирования — это элемент формата. 0 — индекс объекта, строковое значение которого будет вставлено по этой позиции. (Индексы начинаются с 0.) Если объект, который нужно вставить, не является строкой, его ToString метод вызывается для преобразования его в один перед вставкой в результирующую строку.

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

string s = String.Format("At {0}, the temperature is {1}°C.",
                         DateTime.Now, 20.4);
Console.WriteLine(s);
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
String.Format("At {0}, the temperature is {1}°C.", DateTime.Now, 20.4)
|> printfn "%s"
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
Dim s As String = String.Format("At {0}, the temperature is {1}°C.",
                              Date.Now, 20.4)
' Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'

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

Форматирование элементов управления

Вы можете следовать индексу в элементе формата с строкой форматирования, чтобы управлять форматированием объекта. Например, {0:d} применяет строку формата "d" к первому объекту в списке объектов. Ниже приведен пример с одним объектом и двумя элементами формата:

string s = String.Format("It is now {0:d} at {0:t}", DateTime.Now);
Console.WriteLine(s);
// Output similar to: 'It is now 4/10/2015 at 10:04 AM'
String.Format("It is now {0:d} at {0:t}", DateTime.Now)
|> printfn "%s"
// Output similar to: 'It is now 4/10/2015 at 10:04 AM'
Dim s As String = String.Format("It is now {0:d} at {0:t}",
                              Date.Now)
' Output similar to: 'It is now 4/10/2015 at 10:04 AM'

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

Интервалы управления

Ширину строки, вставленной в результирующую строку, можно определить с помощью синтаксиса, например {0,12}, который вставляет 12-символьную строку. В этом случае строковое представление первого объекта выровнено по правому краю в поле 12 символов. (Если строковое представление первого объекта имеет длину более 12 символов, однако предпочтительная ширина поля игнорируется, а в результирующая строка вставляется в строку результата.)

В следующем примере определяется 6-символьное поле для хранения строки "Год" и некоторых строк года, а также 15-символьного поля для хранения строки "Население" и некоторых данных о совокупности. Обратите внимание, что символы выровнены по правому краю в поле.

int[] years = { 2013, 2014, 2015 };
int[] population = { 1025632, 1105967, 1148203 };
var sb = new System.Text.StringBuilder();
sb.Append(String.Format("{0,6} {1,15}\n\n", "Year", "Population"));
for (int index = 0; index < years.Length; index++)
    sb.Append(String.Format("{0,6} {1,15:N0}\n", years[index], population[index]));

Console.WriteLine(sb);

// Result:
//      Year      Population
//
//      2013       1,025,632
//      2014       1,105,967
//      2015       1,148,203
open System
open System.Text
 
let years = [| 2013; 2014; 2015 |]
let population = [| 1025632; 1105967; 1148203 |]
let sb = StringBuilder()
sb.Append(String.Format("{0,6} {1,15}\n\n", "Year", "Population")) |> ignore
for i = 0 to years.Length - 1 do
   sb.Append(String.Format("{0,6} {1,15:N0}\n", years[i], population[i])) |> ignore

printfn $"{sb}"

// Result:
//      Year      Population
//
//      2013       1,025,632
//      2014       1,105,967
//      2015       1,148,203
Dim years() As Integer = {2013, 2014, 2015}
Dim population() As Integer = {1025632, 1105967, 1148203}
Dim sb As New StringBuilder()
sb.Append(String.Format("{0,6} {1,15}{2}{2}",
                       "Year", "Population", vbCrLf))
For index As Integer = 0 To years.Length - 1
    sb.AppendFormat("{0,6} {1,15:N0}{2}",
                  years(index), population(index), vbCrLf)
Next
' Result:
'      Year      Population
'
'      2013       1,025,632
'      2014       1,105,967
'      2015       1,148,203

Выравнивание элементов управления

По умолчанию строки выровнены по правому краю в пределах своего поля, если указать ширину поля. Чтобы выровнять строки по левому краю в поле, вы предусловите ширину поля отрицательным знаком, например {0,-12} для определения 12-символьного левого поля.

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

int[] years = { 2013, 2014, 2015 };
int[] population = { 1025632, 1105967, 1148203 };
String s = String.Format("{0,-10} {1,-10}\n\n", "Year", "Population");
for (int index = 0; index < years.Length; index++)
    s += String.Format("{0,-10} {1,-10:N0}\n",
                       years[index], population[index]);
Console.WriteLine($"\n{s}");
// Result:
//    Year       Population
//
//    2013       1,025,632
//    2014       1,105,967
//    2015       1,148,203
let years = [| 2013; 2014; 2015 |]
let population = [| 1025632; 1105967; 1148203 |]
let mutable s = String.Format("{0,-10} {1,-10}\n\n", "Year", "Population")
for i = 0 to years.Length - 1 do
    s <- s + String.Format("{0,-10} {1,-10:N0}\n", years[i], population[i])
printfn $"\n{s}"
// Result:
//    Year       Population
//
//    2013       1,025,632
//    2014       1,105,967
//    2015       1,148,203
Dim years() As Integer = {2013, 2014, 2015}
Dim population() As Integer = {1025632, 1105967, 1148203}
Dim s As String = String.Format("{0,-10} {1,-10}{2}{2}",
                               "Year", "Population", vbCrLf)
For index As Integer = 0 To years.Length - 1
    s += String.Format("{0,-10} {1,-10:N0}{2}",
                     years(index), population(index), vbCrLf)
Next
' Result:
'    Year       Population
'
'    2013       1,025,632
'    2014       1,105,967
'    2015       1,148,203

String.Format использует функцию составного форматирования. Дополнительные сведения см. в разделе Составное форматирование.

Какой метод вызывается?

По Позвонить
Отформатируйте один или несколько объектов с помощью соглашений текущего языка и региональных параметров. За исключением перегрузки, которые включают provider параметр, остальные Format перегрузки включают String параметр, за которым следует один или несколько параметров объекта. Из-за этого вам не нужно определить, какая Format перегрузка планируется вызвать. Компилятор языка выбирает соответствующую перегрузку из перегрузок, которые не имеют provider параметра, в зависимости от списка аргументов. Например, если в списке аргументов есть пять аргументов, компилятор вызывает Format(String, Object[]) метод.
Отформатируйте один или несколько объектов с помощью соглашений определенного языка и региональных параметров. За каждой Format перегрузкой provider , начинающейся с параметра, следует String параметр и один или несколько параметров объекта. Из-за этого вам не нужно определять конкретную Format перегрузку, которую вы планируете вызвать. Компилятор языка выбирает соответствующую перегрузку из перегрузок, имеющих provider параметр, в зависимости от списка аргументов. Например, если в списке аргументов есть пять аргументов, компилятор вызывает Format(IFormatProvider, String, Object[]) метод.
Выполните пользовательскую операцию форматирования либо с ICustomFormatter реализацией, либо IFormattable реализацией. Любой из четырех перегрузок с параметром provider . Компилятор выбирает соответствующую перегрузку из перегрузок, имеющих provider параметр, на основе списка аргументов.

Метод Format кратко

Каждая перегрузка Format метода использует составную функцию форматирования для включения индексированных заполнителей с нуля, называемых элементами формата в составной строке форматирования. Во время выполнения каждый элемент формата заменяется строковым представлением соответствующего аргумента в списке параметров. Если аргумент имеет nullзначение, элемент форматирования заменяется String.Emptyна . Например, следующий вызов Format(String, Object, Object, Object) метода включает строку формата с тремя элементами формата, {0}{1}и {2}списком аргументов с тремя элементами.

DateTime dat = new DateTime(2012, 1, 17, 9, 30, 0); 
string city = "Chicago";
int temp = -16;
string output = String.Format("At {0} in {1}, the temperature was {2} degrees.",
                              dat, city, temp);
Console.WriteLine(output);
// The example displays output like the following:
//    At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.
open System

let dat = DateTime(2012, 1, 17, 9, 30, 0) 
let city = "Chicago"
let temp = -16
String.Format("At {0} in {1}, the temperature was {2} degrees.", dat, city, temp)
|> printfn "%s"
// The example displays output like the following:
//    At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.
Dim dat As Date = #1/17/2012 9:30AM#
Dim city As String = "Chicago"
Dim temp As Integer = -16
Dim output As String = String.Format("At {0} in {1}, the temperature was {2} degrees.",
                                   dat, city, temp)
Console.WriteLine(output)
' The example displays the following output:
'    At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.

Элемент формата

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

{index[,alignment][:formatString]}

Квадратные скобки указывают необязательные элементы. Необходимы открывающие и закрывающие фигурные скобки. (Чтобы включить литерал открытия или закрытия фигурной скобки в строке формата, см. раздел Экранирование раздела "Фигурные скобки" статьи " Составное форматирование ".)

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

var value = String.Format("{0,-10:C}", 126347.89m);
Console.WriteLine(value);
open System

String.Format("{0,-10:C}", 126347.89m)         
|> printfn "%s"
String.Format("{0,-10:C}", 126347.89D)

Элемент формата содержит следующие элементы:

index
Отсчитываемый от нуля индекс аргумента, строковое представление которого должно быть включено в эту позицию в строке. Если этот аргумент имеет значение null, пустая строка будет включена в эту позицию в строке.

Трассы
Необязательно. Целое число со знаком, указывающее общую длину поля, в которое вставляется аргумент, и является ли он выровнен правым (положительным целым числом) или левым выравниванием (отрицательное целое число). Если не указать выравнивание, строковое представление соответствующего аргумента вставляется в поле без начальных или конечных пробелов.

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

Formatstring
Необязательно. Строка, указывающая формат строки результата соответствующего аргумента. Если не указать formatString, вызывается метод без ToString параметров соответствующего аргумента, чтобы создать его строковое представление. При указании formatString аргумент, на который ссылается элемент формата, должен реализовать IFormattable интерфейс. Типы, поддерживающие строки формата, включают:

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

В следующем примере используются alignment аргументы и formatString аргументы для создания форматированных выходных данных.

// Create array of 5-tuples with population data for three U.S. cities, 1940-1950.
Tuple<string, DateTime, int, DateTime, int>[] cities = 
    { Tuple.Create("Los Angeles", new DateTime(1940, 1, 1), 1504277, 
                   new DateTime(1950, 1, 1), 1970358),
      Tuple.Create("New York", new DateTime(1940, 1, 1), 7454995, 
                   new DateTime(1950, 1, 1), 7891957),  
      Tuple.Create("Chicago", new DateTime(1940, 1, 1), 3396808, 
                   new DateTime(1950, 1, 1), 3620962),  
      Tuple.Create("Detroit", new DateTime(1940, 1, 1), 1623452, 
                   new DateTime(1950, 1, 1), 1849568) };

// Display header
var header = String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}\n",
                              "City", "Year", "Population", "Change (%)");
Console.WriteLine(header);
foreach (var city in cities) {
   var output = String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
                          city.Item1, city.Item2, city.Item3, city.Item4, city.Item5,
                          (city.Item5 - city.Item3)/ (double)city.Item3);
   Console.WriteLine(output);
}
// The example displays the following output:
//    City            Year  Population    Year  Population    Change (%)
//  
//    Los Angeles     1940   1,504,277    1950   1,970,358        31.0 %
//    New York        1940   7,454,995    1950   7,891,957         5.9 %
//    Chicago         1940   3,396,808    1950   3,620,962         6.6 %
//    Detroit         1940   1,623,452    1950   1,849,568        13.9 %
// Create a list of 5-tuples with population data for three U.S. cities, 1940-1950.
let cities = 
    [ "Los Angeles", DateTime(1940, 1, 1), 1504277, DateTime(1950, 1, 1), 1970358
      "New York", DateTime(1940, 1, 1), 7454995, DateTime(1950, 1, 1), 7891957
      "Chicago", DateTime(1940, 1, 1), 3396808, DateTime(1950, 1, 1), 3620962
      "Detroit", DateTime(1940, 1, 1), 1623452, DateTime(1950, 1, 1), 1849568 ]

// Display header
String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}\n", "City", "Year", "Population", "Change (%)")
|> printfn "%s"

for name, year1, pop1, year2, pop2 in cities do
    String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
                  name, year1, pop1, year2, pop2,
                  double (pop2 - pop1) / double pop1)
    |> printfn "%s"
// The example displays the following output:
//    City            Year  Population    Year  Population    Change (%)
//  
//    Los Angeles     1940   1,504,277    1950   1,970,358        31.0 %
//    New York        1940   7,454,995    1950   7,891,957         5.9 %
//    Chicago         1940   3,396,808    1950   3,620,962         6.6 %
//    Detroit         1940   1,623,452    1950   1,849,568        13.9 %
Module Example3
    Public Sub Main()
        ' Create array of 5-tuples with population data for three U.S. cities, 1940-1950.
        Dim cities() =
          {Tuple.Create("Los Angeles", #1/1/1940#, 1504277, #1/1/1950#, 1970358),
            Tuple.Create("New York", #1/1/1940#, 7454995, #1/1/1950#, 7891957),
            Tuple.Create("Chicago", #1/1/1940#, 3396808, #1/1/1950#, 3620962),
            Tuple.Create("Detroit", #1/1/1940#, 1623452, #1/1/1950#, 1849568)}

        ' Display header
        Dim header As String = String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}",
                                           "City", "Year", "Population", "Change (%)")
        Console.WriteLine(header)
        Console.WriteLine()
        For Each city In cities
            Dim output = String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
                                city.Item1, city.Item2, city.Item3, city.Item4, city.Item5,
                                (city.Item5 - city.Item3) / city.Item3)
            Console.WriteLine(output)
        Next
    End Sub
End Module
' The example displays the following output:
'    City            Year  Population    Year  Population    Change (%)
'    
'    Los Angeles     1940   1,504,277    1950   1,970,358        31.0 %
'    New York        1940   7,454,995    1950   7,891,957         5.9 %
'    Chicago         1940   3,396,808    1950   3,620,962         6.6 %
'    Detroit         1940   1,623,452    1950   1,849,568        13.9 %

Форматирование аргументов

Элементы форматирования обрабатываются последовательно с начала строки. Каждый элемент формата имеет индекс, соответствующий объекту в списке аргументов метода. Метод Format извлекает аргумент и получает строковое представление следующим образом:

  • Если аргумент имеет значение null, метод вставляется String.Empty в строку результата. Вам не нужно беспокоиться об обработке NullReferenceException аргументов NULL.

  • При вызове перегрузки Format(IFormatProvider, String, Object[]) и provider реализации объекта IFormatProvider.GetFormat возвращается реализация, отличной от NULL ICustomFormatter , аргумент передается в его ICustomFormatter.Format(String, Object, IFormatProvider) метод. Если элемент формата содержит аргумент formatString , он передается в качестве первого аргумента методу. ICustomFormatter Если реализация доступна и создает непустую строку, эта строка возвращается в виде строкового представления аргумента; в противном случае выполняется следующий шаг.

  • Если аргумент реализует IFormattable интерфейс, его IFormattable.ToString реализация вызывается.

  • Метод без ToString параметров аргумента, который переопределяет или наследует от реализации базового класса, вызывается.

Пример перехвата вызовов ICustomFormatter.Format метода и позволяет просмотреть сведения Format , которые метод передает методу форматирования для каждого элемента форматирования в строке составного формата, см. в примере : поставщик перехвата и римский числовый формататор.

Дополнительные сведения см. в разделе "Порядок обработки".

Форматирование элементов с одинаковым индексом

Метод Format создает FormatException исключение, если индекс элемента индекса больше или равен числу аргументов в списке аргументов. format Однако может содержать больше элементов формата, чем аргументы, если несколько элементов формата имеют один и тот же индекс. В вызове Format(String, Object) метода в следующем примере список аргументов имеет один аргумент, но строка формата включает два элемента формата: один отображает десятичное значение числа, а другой — шестнадцатеричное значение.

short[] values= { Int16.MinValue, -27, 0, 1042, Int16.MaxValue };
Console.WriteLine("{0,10}  {1,10}\n", "Decimal", "Hex");
foreach (short value in values)
{
   string formatString = String.Format("{0,10:G}: {0,10:X}", value);
   Console.WriteLine(formatString);
}   
// The example displays the following output:
//       Decimal         Hex
//    
//        -32768:       8000
//           -27:       FFE5
//             0:          0
//          1042:        412
//         32767:       7FFF
open System

let values= [| Int16.MinValue; -27s; 0s; 1042s; Int16.MaxValue |]
printfn "%10s  %10s\n" "Decimal" "Hex"
for value in values do
    String.Format("{0,10:G}: {0,10:X}", value)
    |> printfn "%s"
// The example displays the following output:
//       Decimal         Hex
//    
//        -32768:       8000
//           -27:       FFE5
//             0:          0
//          1042:        412
//         32767:       7FFF
Module Example1
    Public Sub Main()
        Dim values() As Short = {Int16.MinValue, -27, 0, 1042, Int16.MaxValue}
        Console.WriteLine("{0,10}  {1,10}", "Decimal", "Hex")
        Console.WriteLine()
        For Each value As Short In values
            Dim formatString As String = String.Format("{0,10:G}: {0,10:X}", value)
            Console.WriteLine(formatString)
        Next
    End Sub
End Module
' The example displays the following output:
'       Decimal         Hex
'    
'        -32768:       8000
'           -27:       FFE5
'             0:          0
'          1042:        412
'         32767:       7FFF

Формат и язык и региональные параметры

Как правило, объекты в списке аргументов преобразуются в их строковые представления с помощью соглашений текущего языка и региональных параметров, возвращаемых свойством CultureInfo.CurrentCulture . Это поведение можно контролировать, вызвав одну из перегрузок Format , включающих provider параметр. Параметр provider — это реализация, которая предоставляет пользовательские IFormatProvider и региональные параметры форматирования, используемые для модерации процесса форматирования.

Интерфейс IFormatProvider имеет один член, который отвечает за возврат объекта, GetFormatпредоставляющего сведения о форматировании. .NET имеет три IFormatProvider реализации, которые обеспечивают форматирование, зависящее от языка и региональных параметров:

  • CultureInfo. Его GetFormat метод возвращает объект, зависящий от NumberFormatInfo языка и региональных параметров, для форматирования числовых значений и региональных параметров, а DateTimeFormatInfo также для форматирования значений даты и времени.
  • DateTimeFormatInfo, который используется для форматирования значений даты и времени, зависящих от языка и региональных параметров. Его GetFormat метод возвращает себя.
  • NumberFormatInfo, который используется для форматирования числовых значений, зависящих от языка и региональных параметров. Его GetFormat(Type) метод возвращает себя.

Пользовательские операции форматирования

Можно также вызвать любые перегрузки Format метода с параметром provider типа IFormatProvider для выполнения пользовательских операций форматирования. Например, можно отформатировать целое число как идентификационный номер или номер телефона. Для выполнения настраиваемого IFormatProvider форматирования аргумент provider должен реализовывать как интерфейсы, так и ICustomFormatter интерфейсы. Format Когда метод передает реализацию ICustomFormatter в качестве provider аргумента, Format метод вызывает свою IFormatProvider.GetFormat реализацию и запрашивает объект типаICustomFormatter. Затем он вызывает метод возвращаемого ICustomFormatter объекта Format для форматирования каждого элемента формата в составной строке, переданной ему.

Дополнительные сведения о предоставлении пользовательских решений форматирования см. в разделе "Практическое руководство. Определение и использование пользовательских поставщиков числовых форматов " и ICustomFormatter. Пример преобразования целых чисел в форматированные пользовательские числа см. в примере : операция пользовательского форматирования. Пример преобразования без знака байтов в римские числовые числа см. в примере : поставщик перехвата и римский числовый формататор.

Пример: настраиваемая операция форматирования

В этом примере определяется поставщик формата, который форматирует целочисленное значение в виде номера учетной записи клиента в форме x-xxxxx-xx.

using System;

public class TestFormatter
{
   public static void Main()
   {
      int acctNumber = 79203159;
      Console.WriteLine(String.Format(new CustomerFormatter(), "{0}", acctNumber));
      Console.WriteLine(String.Format(new CustomerFormatter(), "{0:G}", acctNumber));
      Console.WriteLine(String.Format(new CustomerFormatter(), "{0:S}", acctNumber));
      Console.WriteLine(String.Format(new CustomerFormatter(), "{0:P}", acctNumber));
      try {
         Console.WriteLine(String.Format(new CustomerFormatter(), "{0:X}", acctNumber));
      }
      catch (FormatException e) {
         Console.WriteLine(e.Message);
      }
   }
}

public class CustomerFormatter : IFormatProvider, ICustomFormatter
{
   public object GetFormat(Type formatType) 
   {
      if (formatType == typeof(ICustomFormatter))        
         return this; 
      else
         return null;
   }
   
   public string Format(string format, 
                         object arg, 
                         IFormatProvider formatProvider) 
   {                       
      if (! this.Equals(formatProvider))
      {
         return null;
      }
      else
      {
         if (String.IsNullOrEmpty(format)) 
            format = "G";
         
         string customerString = arg.ToString();
         if (customerString.Length < 8)
            customerString = customerString.PadLeft(8, '0');
         
         format = format.ToUpper();
         switch (format)
         {
            case "G":
               return customerString.Substring(0, 1) + "-" +
                                     customerString.Substring(1, 5) + "-" +
                                     customerString.Substring(6);
            case "S":                          
               return customerString.Substring(0, 1) + "/" +
                                     customerString.Substring(1, 5) + "/" +
                                     customerString.Substring(6);
            case "P":                          
               return customerString.Substring(0, 1) + "." +
                                     customerString.Substring(1, 5) + "." +
                                     customerString.Substring(6);
            default:
               throw new FormatException( 
                         String.Format("The '{0}' format specifier is not supported.", format));
         }
      }   
   }
}
// The example displays the following output:
//       7-92031-59
//       7-92031-59
//       7/92031/59
//       7.92031.59
//       The 'X' format specifier is not supported.
open System

type CustomerFormatter() = 
    interface IFormatProvider with
        member this.GetFormat(formatType) =
            if formatType = typeof<ICustomFormatter> then
                this
            else
                null

    interface ICustomFormatter with
        member this.Format(format, arg, formatProvider: IFormatProvider) = 
            if this.Equals formatProvider |> not then
                null
            else
                let format = 
                    if String.IsNullOrEmpty format then "G"
                    else format.ToUpper()
                
                let customerString = 
                    let s = string arg
                    if s.Length < 8 then
                        s.PadLeft(8, '0')
                    else s
                
                match format with
                | "G" ->
                    customerString.Substring(0, 1) + "-" +
                        customerString.Substring(1, 5) + "-" +
                        customerString.Substring 6
                | "S" ->                          
                    customerString.Substring(0, 1) + "/" +
                        customerString.Substring(1, 5) + "/" +
                        customerString.Substring 6
                | "P" ->                          
                    customerString.Substring(0, 1) + "." +
                        customerString.Substring(1, 5) + "." +
                        customerString.Substring 6
                | _ ->
                    raise (FormatException $"The '{format}' format specifier is not supported.")

let acctNumber = 79203159
String.Format(CustomerFormatter(), "{0}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:G}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:S}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:P}", acctNumber)
|> printfn "%s"
try
    String.Format(CustomerFormatter(), "{0:X}", acctNumber)
    |> printfn "%s"
with :? FormatException as e ->
    printfn $"{e.Message}"

// The example displays the following output:
//       7-92031-59
//       7-92031-59
//       7/92031/59
//       7.92031.59
//       The 'X' format specifier is not supported.
Module TestFormatter
   Public Sub Main()
      Dim acctNumber As Integer = 79203159
      Console.WriteLine(String.Format(New CustomerFormatter, "{0}", acctNumber))
      Console.WriteLine(String.Format(New CustomerFormatter, "{0:G}", acctNumber))
      Console.WriteLine(String.Format(New CustomerFormatter, "{0:S}", acctNumber))
      Console.WriteLine(String.Format(New CustomerFormatter, "{0:P}", acctNumber))
      Try
         Console.WriteLine(String.Format(New CustomerFormatter, "{0:X}", acctNumber))
      Catch e As FormatException
         Console.WriteLine(e.Message)
      End Try   
   End Sub
End Module

Public Class CustomerFormatter : Implements IFormatProvider, ICustomFormatter
   Public Function GetFormat(type As Type) As Object  _
                   Implements IFormatProvider.GetFormat
      If type Is GetType(ICustomFormatter) Then
         Return Me
      Else
         Return Nothing
      End If
   End Function
   
   Public Function Format(fmt As String, _
                           arg As Object, _
                           formatProvider As IFormatProvider) As String _
                    Implements ICustomFormatter.Format
      If Not Me.Equals(formatProvider) Then
         Return Nothing
      Else
         If String.IsNullOrEmpty(fmt) Then fmt = "G"
         
         Dim customerString As String = arg.ToString()
         if customerString.Length < 8 Then _
            customerString = customerString.PadLeft(8, "0"c)
         
         Select Case fmt
            Case "G"
               Return customerString.Substring(0, 1) & "-" & _
                                     customerString.Substring(1, 5) & "-" & _
                                     customerString.Substring(6)
            Case "S"                         
               Return customerString.Substring(0, 1) & "/" & _
                                     customerString.Substring(1, 5) & "/" & _
                                     customerString.Substring(6)
            Case "P"
               Return customerString.Substring(0, 1) & "." & _
                                     customerString.Substring(1, 5) & "." & _
                                     customerString.Substring(6)
            Case Else
               Throw New FormatException( _
                         String.Format("The '{0}' format specifier is not supported.", fmt))
         End Select                                                     
      End If   
   End Function
End Class
' The example displays the following output:
'       7-92031-59
'       7-92031-59
'       7/92031/59
'       7.92031.59
'       The 'X' format specifier is not supported.

Пример: поставщик перехвата и римский числовый формататор

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

  • В нем отображаются параметры, переданные в реализацию ICustomFormatter.Format . Это позволяет узнать, какие параметры Format(IFormatProvider, String, Object[]) метод передает в пользовательскую реализацию форматирования для каждого объекта, который он пытается отформатировать. Это может быть полезно при отладке приложения.

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

using System;
using System.Globalization;

public class InterceptProvider : IFormatProvider, ICustomFormatter
{
   public object GetFormat(Type formatType)
   {
      if (formatType == typeof(ICustomFormatter))
         return this;
      else
         return null;
   }
   
   public string Format(String format, Object obj, IFormatProvider provider) 
   {
      // Display information about method call.
      string formatString = format ?? "<null>";
      Console.WriteLine("Provider: {0}, Object: {1}, Format String: {2}",
                        provider.GetType().Name, obj ?? "<null>", formatString);
                        
      if (obj == null) return String.Empty;
            
      // If this is a byte and the "R" format string, format it with Roman numerals.
      if (obj is Byte && formatString.ToUpper().Equals("R")) {
         Byte value = (Byte) obj;
         int remainder;
         int result;
         String returnString = String.Empty;

         // Get the hundreds digit(s)
         result = Math.DivRem(value, 100, out remainder);
         if (result > 0)  
            returnString = new String('C', result);
         value = (Byte) remainder;
         // Get the 50s digit
         result = Math.DivRem(value, 50, out remainder);
         if (result == 1)
            returnString += "L";
         value = (Byte) remainder;
         // Get the tens digit.
         result = Math.DivRem(value, 10, out remainder);
         if (result > 0)
            returnString += new String('X', result);
         value = (Byte) remainder; 
         // Get the fives digit.
         result = Math.DivRem(value, 5, out remainder);
         if (result > 0)
            returnString += "V";
         value = (Byte) remainder;
         // Add the ones digit.
         if (remainder > 0) 
            returnString += new String('I', remainder);
         
         // Check whether we have too many X characters.
         int pos = returnString.IndexOf("XXXX");
         if (pos >= 0) {
            int xPos = returnString.IndexOf("L"); 
            if (xPos >= 0 & xPos == pos - 1)
               returnString = returnString.Replace("LXXXX", "XC");
            else
               returnString = returnString.Replace("XXXX", "XL");   
         }
         // Check whether we have too many I characters
         pos = returnString.IndexOf("IIII");
         if (pos >= 0)
            if (returnString.IndexOf("V") >= 0)
               returnString = returnString.Replace("VIIII", "IX");
            else
               returnString = returnString.Replace("IIII", "IV");    

         return returnString; 
      }   

      // Use default for all other formatting.
      if (obj is IFormattable)
         return ((IFormattable) obj).ToString(format, CultureInfo.CurrentCulture);
      else
         return obj.ToString();
   }
}

public class Example
{
   public static void Main()
   {
      int n = 10;
      double value = 16.935;
      DateTime day = DateTime.Now;
      InterceptProvider provider = new InterceptProvider();
      Console.WriteLine(String.Format(provider, "{0:N0}: {1:C2} on {2:d}\n", n, value, day));
      Console.WriteLine(String.Format(provider, "{0}: {1:F}\n", "Today: ", 
                                      (DayOfWeek) DateTime.Now.DayOfWeek));
      Console.WriteLine(String.Format(provider, "{0:X}, {1}, {2}\n", 
                                      (Byte) 2, (Byte) 12, (Byte) 199));
      Console.WriteLine(String.Format(provider, "{0:R}, {1:R}, {2:R}\n", 
                                      (Byte) 2, (Byte) 12, (Byte) 199));
   }
}
// The example displays the following output:
//    Provider: InterceptProvider, Object: 10, Format String: N0
//    Provider: InterceptProvider, Object: 16.935, Format String: C2
//    Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
//    10: $16.94 on 1/31/2013
//    
//    Provider: InterceptProvider, Object: Today: , Format String: <null>
//    Provider: InterceptProvider, Object: Thursday, Format String: F
//    Today: : Thursday
//    
//    Provider: InterceptProvider, Object: 2, Format String: X
//    Provider: InterceptProvider, Object: 12, Format String: <null>
//    Provider: InterceptProvider, Object: 199, Format String: <null>
//    2, 12, 199
//    
//    Provider: InterceptProvider, Object: 2, Format String: R
//    Provider: InterceptProvider, Object: 12, Format String: R
//    Provider: InterceptProvider, Object: 199, Format String: R
//    II, XII, CXCIX
open System
open System.Globalization

type InterceptProvider() =
    interface IFormatProvider with
        member this.GetFormat(formatType) =
            if formatType = typeof<ICustomFormatter> then
                this
            else
                null
    interface ICustomFormatter with
        member _.Format(format, obj, provider: IFormatProvider) = 
            // Display information about method call.
            let formatString =
                if format = null then "<null>" else format
            printfn $"Provider: {provider.GetType().Name}, Object: %A{obj}, Format String: %s{formatString}"
                                
            if obj = null then
                String.Empty
            else
                // If this is a byte and the "R" format string, format it with Roman numerals.
                match obj with
                | :? byte as value when formatString.ToUpper().Equals "R" -> 
                    let mutable returnString = String.Empty

                    // Get the hundreds digit(s)
                    let struct (result, remainder) = Math.DivRem(value, 100uy)
                    if result > 0uy then
                        returnString <- String('C', int result)
                    let value = byte remainder
                    // Get the 50s digit
                    let struct (result, remainder) = Math.DivRem(value, 50uy)
                    if result = 1uy then
                        returnString <- returnString + "L"
                    let value = byte remainder
                    // Get the tens digit.
                    let struct (result, remainder) = Math.DivRem(value, 10uy)
                    if result > 0uy then
                        returnString <- returnString + String('X', int result)
                    let value = byte remainder 
                    // Get the fives digit.
                    let struct (result, remainder) = Math.DivRem(value, 5uy)
                    if result > 0uy then
                        returnString <- returnString + "V"
                    let value = byte remainder
                    // Add the ones digit.
                    if remainder > 0uy then 
                        returnString <- returnString + String('I', int remainder)
                    
                    // Check whether we have too many X characters.
                    let pos = returnString.IndexOf "XXXX"
                    if pos >= 0 then
                        let xPos = returnString.IndexOf "L" 
                        returnString <-
                            if xPos >= 0 && xPos = pos - 1 then
                                returnString.Replace("LXXXX", "XC")
                            else
                                returnString.Replace("XXXX", "XL")   
                    // Check whether we have too many I characters
                    let pos = returnString.IndexOf "IIII"
                    if pos >= 0 then
                        returnString <-
                            if returnString.IndexOf "V" >= 0 then
                                returnString.Replace("VIIII", "IX")
                            else
                                returnString.Replace("IIII", "IV")    
                    returnString 

                // Use default for all other formatting.
                | :? IFormattable as x ->
                    x.ToString(format, CultureInfo.CurrentCulture)
                | _ ->
                    string obj

let n = 10
let value = 16.935
let day = DateTime.Now
let provider = InterceptProvider()
String.Format(provider, "{0:N0}: {1:C2} on {2:d}\n", n, value, day)
|> printfn "%s"
String.Format(provider, "{0}: {1:F}\n", "Today: ", DateTime.Now.DayOfWeek)
|> printfn "%s"
String.Format(provider, "{0:X}, {1}, {2}\n", 2uy, 12uy, 199uy)
|> printfn "%s"
String.Format(provider, "{0:R}, {1:R}, {2:R}\n", 2uy, 12uy, 199uy)
|> printfn "%s"
// The example displays the following output:
//    Provider: InterceptProvider, Object: 10, Format String: N0
//    Provider: InterceptProvider, Object: 16.935, Format String: C2
//    Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
//    10: $16.94 on 1/31/2013
//    
//    Provider: InterceptProvider, Object: Today: , Format String: <null>
//    Provider: InterceptProvider, Object: Thursday, Format String: F
//    Today: : Thursday
//    
//    Provider: InterceptProvider, Object: 2, Format String: X
//    Provider: InterceptProvider, Object: 12, Format String: <null>
//    Provider: InterceptProvider, Object: 199, Format String: <null>
//    2, 12, 199
//    
//    Provider: InterceptProvider, Object: 2, Format String: R
//    Provider: InterceptProvider, Object: 12, Format String: R
//    Provider: InterceptProvider, Object: 199, Format String: R
//    II, XII, CXCIX
Imports System.Globalization

Public Class InterceptProvider : Implements IFormatProvider, ICustomFormatter
   Public Function GetFormat(formatType As Type) As Object _
         Implements IFormatProvider.GetFormat
      If formatType Is GetType(ICustomFormatter) Then
         Return Me
      Else
         Return Nothing
      End If
   End Function
   
   Public Function Format(fmt As String, obj As Object, provider As IFormatProvider) As String _
         Implements ICustomFormatter.Format

      Dim formatString As String = If(fmt IsNot Nothing, fmt, "<null>")
      Console.WriteLine("Provider: {0}, Object: {1}, Format String: {2}",
                        provider, If(obj IsNot Nothing, obj, "<null>"), formatString)

      If obj Is Nothing Then Return String.Empty
            
      ' If this is a byte and the "R" format string, format it with Roman numerals.
      If TypeOf(obj) Is Byte AndAlso formatString.ToUpper.Equals("R") Then
         Dim value As Byte = CByte(obj)
         Dim remainder As Integer
         Dim result As Integer
         Dim returnString As String = String.Empty

         ' Get the hundreds digit(s)
         result = Math.DivRem(value, 100, remainder)
         If result > 0 Then returnString = New String("C"c, result)
         value = CByte(remainder)
         ' Get the 50s digit
         result = Math.DivRem(value, 50, remainder)
         If result = 1 Then returnString += "L"
         value = CByte(remainder)
         ' Get the tens digit.
         result = Math.DivRem(value, 10, remainder)
         If result > 0 Then returnString += New String("X"c, result)
         value = CByte(remainder) 
         ' Get the fives digit.
         result = Math.DivRem(value, 5, remainder)
         If result > 0 Then returnString += "V"
         value = CByte(remainder)
         ' Add the ones digit.
         If remainder > 0 Then returnString += New String("I"c, remainder)
         
         ' Check whether we have too many X characters.
         Dim pos As Integer = returnString.IndexOf("XXXX")
         If pos >= 0 Then
            Dim xPos As Integer = returnString.IndexOf("L") 
            If xPos >= 0 And xPos = pos - 1 Then
               returnString = returnString.Replace("LXXXX", "XC")
            Else
               returnString = returnString.Replace("XXXX", "XL")   
            End If         
         End If
         ' Check whether we have too many I characters
         pos = returnString.IndexOf("IIII")
         If pos >= 0 Then
            If returnString.IndexOf("V") >= 0 Then
               returnString = returnString.Replace("VIIII", "IX")
            Else
               returnString = returnString.Replace("IIII", "IV")    
            End If
         End If
         Return returnString 
      End If   

      ' Use default for all other formatting.
      If obj Is GetType(IFormattable)
         Return CType(obj, IFormattable).ToString(fmt, CultureInfo.CurrentCulture)
      Else
         Return obj.ToString()
      End If
   End Function
End Class

Module Example
   Public Sub Main()
      Dim n As Integer = 10
      Dim value As Double = 16.935
      Dim day As DateTime = Date.Now
      Dim provider As New InterceptProvider()
      Console.WriteLine(String.Format(provider, "{0:N0}: {1:C2} on {2:d}", n, value, day))
      Console.WriteLine()
      Console.WriteLine(String.Format(provider, "{0}: {1:F}", "Today", 
                                      CType(Date.Now.DayOfWeek, DayOfWeek)))
      Console.WriteLine()
      Console.WriteLine(String.Format(provider, "{0:X}, {1}, {2}\n", 
                                      CByte(2), CByte(12), CByte(199)))
      Console.WriteLine()
      Console.WriteLine(String.Format(provider, "{0:R}, {1:R}, {2:R}", 
                                      CByte(2), CByte(12), CByte(199)))
   End Sub
End Module
' The example displays the following output:
'    Provider: InterceptProvider, Object: 10, Format String: N0
'    Provider: InterceptProvider, Object: 16.935, Format String: C2
'    Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
'    10: $16.94 on 1/31/2013
'    
'    Provider: InterceptProvider, Object: Today: , Format String: <null>
'    Provider: InterceptProvider, Object: Thursday, Format String: F
'    Today: : Thursday
'    
'    Provider: InterceptProvider, Object: 2, Format String: X
'    Provider: InterceptProvider, Object: 12, Format String: <null>
'    Provider: InterceptProvider, Object: 199, Format String: <null>
'    2, 12, 199
'    
'    Provider: InterceptProvider, Object: 2, Format String: R
'    Provider: InterceptProvider, Object: 12, Format String: R
'    Provider: InterceptProvider, Object: 199, Format String: R
'    II, XII, CXCIX

Вопросы и ответы

Почему рекомендуется интерполяция строк для вызовов String.Format метода?

Интерполяция строк:

  • Более гибкий. Его можно использовать в любой строке без вызова метода, поддерживающего составное форматирование. В противном случае необходимо вызвать Format метод или другой метод, поддерживающий составное форматирование, например Console.WriteLine или StringBuilder.AppendFormat.

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

Сравнение следующих двух примеров кода иллюстрирует превосходство интерполированных строк над объединением строк и вызовами составных методов форматирования. Использование нескольких операций объединения строк в следующем примере создает подробный и сложный код.

string[] names = { "Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma" };
string output = names[0] + ", " + names[1] + ", " + names[2] + ", " +
                names[3] + ", " + names[4] + ", " + names[5] + ", " +
                names[6];

output += "\n";
var date = DateTime.Now;
output += String.Format("It is {0:t} on {0:d}. The day of the week is {1}.",
                        date, date.DayOfWeek);
Console.WriteLine(output);
// The example displays the following output:
//     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
//     It is 10:29 AM on 1/8/2018. The day of the week is Monday.
open System

let names = [| "Balto"; "Vanya"; "Dakota"; "Samuel"; "Koani"; "Yiska"; "Yuma" |]
let output = 
    names[0] + ", " + names[1] + ", " + names[2] + ", " + 
    names[3] + ", " + names[4] + ", " + names[5] + ", " + 
    names[6] + "\n"

let date = DateTime.Now
output + String.Format("It is {0:t} on {0:d}. The day of the week is {1}.", date, date.DayOfWeek)
|> printfn "%s"
// The example displays the following output:
//     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
//     It is 10:29 AM on 1/8/2018. The day of the week is Monday.

Module Example12
    Public Sub Main()
        Dim names = {"Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma"}
        Dim output = names(0) + ", " + names(1) + ", " + names(2) + ", " +
                   names(3) + ", " + names(4) + ", " + names(5) + ", " +
                   names(6)

        output += vbCrLf
        Dim dat = DateTime.Now
        output += String.Format("It is {0:t} on {0:d}. The day of the week is {1}.",
                              dat, dat.DayOfWeek)
        Console.WriteLine(output)
    End Sub
End Module
' The example displays the following output:
'     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
'     It is 10:29 AM on 1/8/2018. The day of the week is Monday.

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

string[] names = { "Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma" };
string output = $"{names[0]}, {names[1]}, {names[2]}, {names[3]}, {names[4]}, " +
                $"{names[5]}, {names[6]}";

var date = DateTime.Now;
output += $"\nIt is {date:t} on {date:d}. The day of the week is {date.DayOfWeek}.";
Console.WriteLine(output);
// The example displays the following output:
//     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
//     It is 10:29 AM on 1/8/2018. The day of the week is Monday.
open System

let names = [| "Balto"; "Vanya"; "Dakota"; "Samuel"; "Koani"; "Yiska"; "Yuma" |]
let output = $"{names[0]}, {names[1]}, {names[2]}, {names[3]}, {names[4]}, {names[5]}, {names[6]}"  

let date = DateTime.Now
output + $"\nIt is {date:t} on {date:d}. The day of the week is {date.DayOfWeek}."
|> printfn "%s" 
// The example displays the following output:
//     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
//     It is 10:29 AM on 1/8/2018. The day of the week is Monday.

Module Example13
    Public Sub Main()
        Dim names = {"Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma"}
        Dim output = $"{names(0)}, {names(1)}, {names(2)}, {names(3)}, {names(4)}, " +
                   $"{names(5)}, {names(6)}"

        Dim dat = DateTime.Now
        output += $"{vbCrLf}It is {dat:t} on {dat:d}. The day of the week is {dat.DayOfWeek}."
        Console.WriteLine(output)
    End Sub
End Module
' The example displays the following output:
'     Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
'     It is 10:29 AM on 1/8/2018. The day of the week is Monday.

Где можно найти предопределенные строки формата?

Разделы справки управлять выравниванием строк результатов, заменяющих элементы форматирования?

Общий синтаксис элемента формата:

{index[,alignment][: formatString]}

Где выравнивание — это целое число со знаком, определяющее ширину поля. Если это значение отрицательное, текст в поле выровнен по левому краю. Если это положительно, текст выровнен по правому краю.

Разделы справки управлять числом цифр после десятичного разделителя?

Все строки стандартного числового формата, кроме "D" (который используется только с целыми числами), "G", "R" и "X" позволяют описатель точности, определяющий число десятичных цифр в результирующей строке. В следующем примере используются стандартные числовые строки формата для управления числом десятичных цифр в результирующем строке.

object[] values = { 1603, 1794.68235, 15436.14 };
string result;
foreach (var value in values)
{
    result = String.Format("{0,12:C2}   {0,12:E3}   {0,12:F4}   {0,12:N3}  {1,12:P2}\n",
                           Convert.ToDouble(value), Convert.ToDouble(value) / 10000);
    Console.WriteLine(result);
}
// The example displays output like the following:
//       $1,603.00     1.603E+003      1603.0000      1,603.000       16.03 %
//    
//       $1,794.68     1.795E+003      1794.6824      1,794.682       17.95 %
//    
//      $15,436.14     1.544E+004     15436.1400     15,436.140      154.36 %
open System

let values: obj list = [ 1603, 1794.68235, 15436.14 ]
for value in values do
   String.Format("{0,12:C2}   {0,12:E3}   {0,12:F4}   {0,12:N3}  {1,12:P2}\n", Convert.ToDouble(value), Convert.ToDouble(value) / 10000.)
   |> printfn "%s"
// The example displays output like the following:
//       $1,603.00     1.603E+003      1603.0000      1,603.000       16.03 %
//    
//       $1,794.68     1.795E+003      1794.6824      1,794.682       17.95 %
//    
//      $15,436.14     1.544E+004     15436.1400     15,436.140      154.36 %
Module Example7
    Public Sub Main()
        Dim values() As Object = {1603, 1794.68235, 15436.14}
        Dim result As String
        For Each value In values
            result = String.Format("{0,12:C2}   {0,12:E3}   {0,12:F4}   {0,12:N3}  {1,12:P2}",
                                value, CDbl(value) / 10000)
            Console.WriteLine(result)
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'       $1,603.00     1.603E+003      1603.0000      1,603.000       16.03 %
'    
'       $1,794.68     1.795E+003      1794.6824      1,794.682       17.95 %
'    
'      $15,436.14     1.544E+004     15436.1400     15,436.140      154.36 %

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

decimal value = 16309.5436m;
string result = String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}",
                              value);
Console.WriteLine(result);
// The example displays the following output:
//        16309.54360    16,309.54    16309.544
let value = 16309.5436m
String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}", value)
|> printfn "%s"
// The example displays the following output:
//        16309.54360    16,309.54    16309.544
Module Example8
    Public Sub Main()
        Dim value As Decimal = 16309.5436D
        Dim result As String = String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}",
                                           value)
        Console.WriteLine(result)
    End Sub
End Module
' The example displays the following output:
'    16309.54360    16,309.54    16309.544

Разделы справки управлять числом целочисленных цифр?

По умолчанию операции форматирования отображают только ненулевых целочисленных цифр. При форматировании целых чисел можно использовать описатель точности со строками стандартного формата "D" и "X" для управления числом цифр.

int value = 1326;
string result = String.Format("{0,10:D6} {0,10:X8}", value);
Console.WriteLine(result);
// The example displays the following output:
//     001326   0000052E
open System

let value = 1326
String.Format("{0,10:D6} {0,10:X8}", value)
|> printfn "%s"
// The example displays the following output:
//     001326   0000052E
Module Example10
    Public Sub Main()
        Dim value As Integer = 1326
        Dim result As String = String.Format("{0,10:D6} {0,10:X8}", value)
        Console.WriteLine(result)
    End Sub
End Module
' The example displays the following output:
'       001326   0000052E

Целочисленное число или число с плавающей запятой можно навести начальные нули для создания строки результата с указанным числом целочисленных цифр с помощью описатель пользовательского числового формата "0", как показано в следующем примере.

int value = 16342;
string result = String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}",
                              value);
Console.WriteLine(result);
// The example displays the following output:
//           00016342       00016342.000    0,000,016,342.0
open System

let value = 16342
String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}", value)
|> printfn "%s"
// The example displays the following output:
//           00016342       00016342.000    0,000,016,342.0
Module Example9
    Public Sub Main()
        Dim value As Integer = 16342
        Dim result As String = String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}",
                                           value)
        Console.WriteLine(result)
    End Sub
End Module
' The example displays the following output:
'           00016342       00016342.000    0,000,016,342.0

Сколько элементов можно включить в список форматов?

Нет практического ограничения. Второй параметр Format(IFormatProvider, String, Object[]) метода помечен ParamArrayAttribute атрибутом, что позволяет включать список разделителей или массив объектов в качестве списка форматов.

Разделы справки включать литеральные скобки ("{" и "}") в строку результата?

Например, как запретить следующему вызову метода вызвать FormatException исключение?

result = String.Format("The text has {0} '{' characters and {1} '}' characters.",
                       nOpen, nClose);
let result = 
    String.Format("The text has {0} '{' characters and {1} '}' characters.", nOpen, nClose)
result = String.Format("The text has {0} '{' characters and {1} '}' characters.",
                 nOpen, nClose)

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

string result;
int nOpen = 1;
int nClose = 2;
result = String.Format("The text has {0} '{{' characters and {1} '}}' characters.",
                       nOpen, nClose);
Console.WriteLine(result);
let result =
    String.Format("The text has {0} '{{' characters and {1} '}}' characters.", nOpen, nClose)
result = String.Format("The text has {0} '{{' characters and {1} '}}' characters.",
                 nOpen, nClose)

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

string result;
int nOpen = 1;
int nClose = 2;
result = String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.",
                       nOpen, "{", nClose, "}");
Console.WriteLine(result);
let result =
    String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.", nOpen, "{", nClose, "}")
result = String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.",
                 nOpen, "{", nClose, "}")

Почему вызов метода String.Format вызывает формат FormatException?

Наиболее распространенной причиной исключения является то, что индекс элемента формата не соответствует объекту в списке форматов. Обычно это означает, что индексы элементов форматирования были неправильно указаны или вы забыли включить объект в список форматов. При попытке включить неискаченный левый или правый символ фигурной скобки FormatExceptionтакже вызывается. Иногда исключение является результатом опечатки; Например, типичная ошибка заключается в неправильном вводе "[" (левая скобка) вместо "{" (левая скобка).

Если метод Format(System.IFormatProvider,System.String,System.Object[]) поддерживает массивы параметров, почему мой код создает исключение при использовании массива?

Например, следующий код вызывает FormatException исключение:

Random rnd = new Random();
int[] numbers = new int[4];
int total = 0;
for (int ctr = 0; ctr <= 2; ctr++)
{
    int number = rnd.Next(1001);
    numbers[ctr] = number;
    total += number;
}
numbers[3] = total;
Console.WriteLine("{0} + {1} + {2} = {3}", numbers);
open System

let rnd = Random()
let mutable total = 0
let numbers = Array.zeroCreate<int> 4
for i = 0 to 2 do
   let number = rnd.Next 1001
   numbers[i] <- number
   total <- total + number
numbers[3] <- total
Console.WriteLine("{0} + {1} + {2} = {3}", numbers)
Imports System.Collections.Generic

Module Example5
    Public Sub Main()
        Dim rnd As New Random()
        Dim numbers(3) As Integer
        Dim total As Integer = 0
        For ctr = 0 To 2
            Dim number As Integer = rnd.Next(1001)
            numbers(ctr) = number
            total += number
        Next
        numbers(3) = total
        Console.WriteLine("{0} + {1} + {2} = {3}", numbers)
    End Sub
End Module

Это проблема разрешения перегрузки компилятора. Так как компилятор не может преобразовать массив целых чисел в массив объектов, он обрабатывает целый массив как один аргумент, поэтому вызывает Format(String, Object) метод. Исключение возникает из-за четырех элементов формата, но только одного элемента в списке форматов.

Так как ни Visual Basic, ни C# не могут преобразовать целый массив в массив объектов, перед вызовом Format(String, Object[]) метода необходимо выполнить преобразование самостоятельно. В следующем примере показано, как это делается.

Random rnd = new Random();
int[] numbers = new int[4];
int total = 0;
for (int ctr = 0; ctr <= 2; ctr++)
{
    int number = rnd.Next(1001);
    numbers[ctr] = number;
    total += number;
}
numbers[3] = total;
object[] values = new object[numbers.Length];
numbers.CopyTo(values, 0);
Console.WriteLine("{0} + {1} + {2} = {3}", values);
open System

let rnd = Random()
let numbers = Array.zeroCreate<int> 4
let mutable total = 0
for i = 0 to 2 do
   let number = rnd.Next 1001
   numbers[i] <- number
   total <- total + number
numbers[3] <- total
let values = Array.zeroCreate<obj> numbers.Length
numbers.CopyTo(values, 0)
Console.WriteLine("{0} + {1} + {2} = {3}", values)
Imports System.Collections.Generic

Module Example6
    Public Sub Main()
        Dim rnd As New Random()
        Dim numbers(3) As Integer
        Dim total As Integer = 0
        For ctr = 0 To 2
            Dim number As Integer = rnd.Next(1001)
            numbers(ctr) = number
            total += number
        Next
        numbers(3) = total
        Dim values(numbers.Length - 1) As Object
        numbers.CopyTo(values, 0)
        Console.WriteLine("{0} + {1} + {2} = {3}", values)
    End Sub
End Module