Типы форматирования

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

  • Внутреннее представление значений необязательно соответствует тому виду, в котором они должны быть представлены пользователям. Например, номер телефона может храниться в форме 8009999999, которая не отличается удобством для пользователей. Вместо этого номер должен отображаться в следующем виде: 800-999-9999.

  • Иногда порядок преобразования объекта в строковое представление неочевиден. Например, неясно, как должно выглядеть строковое представление объекта класса Temperature, представляющего температурные значения, или класса Person, представляющего данные о людях.

  • Для некоторых значений может потребоваться форматирование, учитывающее язык и региональные параметры. Например, в приложении, где числа используются для обозначения денежных сумм, числовые строки должны включать символ текущей валюты, разделители групп (в большинстве случаев они совпадают с разделителями тысяч) и символ-разделитель целой и дробной частей.

  • Одно и то же значение может быть необходимо представить в приложении несколькими способами. Например, приложение может представлять элемент перечисления, отображая строковое представление его имени или его базовое значение.

ПримечаниеПримечание

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

Платформа .NET Framework обеспечивает обширную поддержку форматирования, позволяя разработчикам справиться с описанными проблемами.

Обзор включает следующие разделы.

  • Форматирование в платформе .NET Framework

  • Форматирование по умолчанию с помощью метода ToString

  • Переопределение метода ToString

  • Метод ToString и строки формата

  • Поставщики форматирования и интерфейс IFormatProvider

  • Интерфейс IFormattable

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

  • Настраиваемое форматирование с использованием интерфейса ICustomFormatter

  • Связанные разделы

  • Ссылки

Форматирование в платформе .NET Framework

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

  • Переопределение метода Object.ToString, позволяющее определить настраиваемое строковое представление значения объекта. Дополнительные сведения см. ниже в подразделе Переопределение метода ToString.

  • Определение описателей формата, позволяющих использовать несколько видов строкового представления значения объекта. Например, описатель формата "X" в следующем операторе позволяет преобразовать целое число в шестнадцатеричное строковое представление.

    Console.WriteLine(integerValue.ToString("X"))   ' Displays EB98.
    
    Console.WriteLine(integerValue.ToString("X"));   // Displays EB98.
    

    Дополнительные сведения об описателях форматов см. в подразделе Метод ToString и строки формата.

  • Использование поставщиков форматирования, позволяющих воспользоваться преимуществами соглашений о форматировании, присущих конкретному языку и региональным параметрам. Например, следующий оператор выводит значение валюты с использованием соглашений о форматировании языка и региональных параметров "en-US".

    Console.WriteLine(cost.ToString("C", New System.Globalization.CultureInfo("en-US")))
    ' The example displays the following output:
    '       $1,632.54
    
    Console.WriteLine(cost.ToString("C", 
                      new System.Globalization.CultureInfo("en-US")));   
    // The example displays the following output:
    //       $1,632.54
    

    Дополнительные сведения о форматировании с помощью поставщиков форматирования см. в подразделе Поставщики форматирования и интерфейс IFormatProvider.

  • Реализация интерфейса IFormattable, позволяющая преобразовывать строки с помощью класса Convert и использовать составное форматирование. Дополнительные сведения см. в подразделе Интерфейс IFormattable.

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

  • Реализация интерфейсов ICustomFormatter и IFormatProvider, позволяющая создать полноценное настраиваемое решение для форматирования. Дополнительные сведения см. в подразделе Настраиваемое форматирование с использованием интерфейса ICustomFormatter.

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

К началу

Форматирование по умолчанию с помощью метода ToString

Любой производный от System.Object тип автоматически наследует метод ToString без параметров, по умолчанию возвращающий имя типа. В следующем примере демонстрируется использование метода ToString по умолчанию. Здесь определен класс с именем Automobile, у которого нет реализации. При создании экземпляра этого класса и вызове его метода ToString отображается имя класса.

Public Class Automobile
   ' No implementation. All members are inherited from Object.
End Class

Module Example
   Public Sub Main()
      Dim firstAuto As New Automobile()
      Console.WriteLine(firstAuto)
   End Sub
End Module
' The example displays the following output:
'       Automobile
using System;

public class Automobile
{
   // No implementation. All members are inherited from Object.
}

public class Example
{
   public static void Main()
   {
      Automobile firstAuto = new Automobile();
      Console.WriteLine(firstAuto);
   }
}
// The example displays the following output:
//       Automobile

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

ПримечаниеПримечание

Структуры наследуют от типа ValueType, который также является наследником Object.Хотя в ValueType метод Object.ToString переопределен, его реализация идентична базовой.

К началу

Переопределение метода ToString

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

Public Class Temperature
   Private temp As Decimal

   Public Sub New(temperature As Decimal)
      Me.temp = temperature
   End Sub

   Public Overrides Function ToString() As String
      Return Me.temp.ToString("N1") + "°C"   
   End Function
End Class

Module Example
   Public Sub Main()
      Dim currentTemperature As New Temperature(23.6d)
      Console.WriteLine("The current temperature is {0}.", currentTemperature)
   End Sub
End Module
' The example displays the following output:
'       The current temperature is 23.6°C.
using System;

public class Temperature
{
   private decimal temp;

   public Temperature(decimal temperature)
   {
      this.temp = temperature;   
   }

   public override string ToString()
   {
      return this.temp.ToString("N1") + "°C";
   }
}

public class Example
{
   public static void Main()
   {
      Temperature currentTemperature = new Temperature(23.6m);
      Console.WriteLine("The current temperature is {0}.", currentTemperature);
   }
}
// The example displays the following output:
//       The current temperature is 23.6°C.

В платформе .NET Framework метод ToString переопределен у всех типов-примитивов значений: вместо имени он отображает значение объекта. В следующей таблице показаны переопределения для всех типов-примитивов. Обратите внимание, что большинство переопределенных методов вызывают другую перегрузку метода ToString и передают ей описатель формата "G", который задает общий формат типа, и объект IFormatProvider, представляющий текущий язык и региональные параметры.

Тип

Переопределение ToString

Boolean

Возвращает Boolean.TrueString или Boolean.FalseString.

Byte

Вызывает метод Byte.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Byte в соответствии с текущим языком и региональными параметрами.

Char

Возвращает символ в виде строки.

DateTime

Вызывает метод DateTime.ToString("G", DatetimeFormatInfo.CurrentInfo), чтобы отформатировать значение даты и времени в соответствии с текущим языком и региональными параметрами.

Decimal

Вызывает метод Decimal.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Decimal в соответствии с текущим языком и региональными параметрами.

Double

Вызывает метод Double.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Double в соответствии с текущим языком и региональными параметрами.

Int16

Вызывает метод Int16.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Int16 в соответствии с текущим языком и региональными параметрами.

Int32

Вызывает метод Int32.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Int32 в соответствии с текущим языком и региональными параметрами.

Int64

Вызывает метод Int64.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Int64 в соответствии с текущим языком и региональными параметрами.

SByte

Вызывает метод SByte.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение SByte в соответствии с текущим языком и региональными параметрами.

Single

Вызывает метод Single.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение Single в соответствии с текущим языком и региональными параметрами.

UInt16

Вызывает метод UInt16.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение UInt16 в соответствии с текущим языком и региональными параметрами.

UInt32

Вызывает метод UInt32.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение UInt32 в соответствии с текущим языком и региональными параметрами.

UInt64

Вызывает метод UInt64.ToString("G", NumberFormatInfo.CurrentInfo), чтобы отформатировать значение UInt64 в соответствии с текущим языком и региональными параметрами.

К началу

Метод ToString и строки формата

Использовать метод ToString по умолчанию или его перегрузку удобно, если у объекта имеется однозначное строковое представление. Тем не менее зачастую значение объекта может иметь несколько представлений. Например, температура может выражаться в градусах по шкале Фаренгейта, Цельсия или Кельвина. Аналогично, целое число 10 можно представить различными способами, включая 10, 10.0, 1.0e01 или $10.00.

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

Все числовые типы, типы даты и времени, а также перечисления в составе платформы .NET Framework поддерживают предопределенный набор описателей формата. Строки формата также можно использовать для определения разнообразных строковых представлений прикладных пользовательских типов данных.

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

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

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

Строки стандартного формата для типов перечислений напрямую определяют строковое представление значения. От строки формата, переданной в метод ToString значения перечисления, зависит, будет оно представлено своим строковым именем (описатели формата "G" и "F"), базовым целочисленным значением (описатель формата "D") или шестидесятеричным значением (описатель формата "X"). В следующем примере демонстрируется использование строк стандартного формата для форматирования значения перечисления DayOfWeek.

Dim thisDay As DayOfWeek = DayOfWeek.Monday
Dim formatStrings() As String = {"G", "F", "D", "X"}

For Each formatString As String In formatStrings
   Console.WriteLine(thisDay.ToString(formatString))
Next
' The example displays the following output:
'       Monday
'       Monday
'       1
'       00000001
DayOfWeek thisDay = DayOfWeek.Monday;
string[] formatStrings = {"G", "F", "D", "X"};

foreach (string formatString in formatStrings)
   Console.WriteLine(thisDay.ToString(formatString));
// The example displays the following output:
//       Monday
//       Monday
//       1
//       00000001

Сведения о строках формата перечислений см. в разделе Строки форматов перечисления.

Строки стандартного формата для числовых типов обычно задают результирующую строку, точный вид которой зависит от значения одного или нескольких свойств. Например, описатель формата "C" форматирует число в виде значения валюты. При вызове метода ToString с описателем формата "C" в качестве единственного параметра для определения строкового представления числового значения используются следующие свойства объекта NumberFormatInfo для текущего языка и региональных параметров:

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

  • Свойство CurrencyNegativePattern или CurrencyPositivePattern, возвращающее целое число, от которого зависит следующее:

    • Положение символа валюты.

    • Обозначение отрицательных значений: отрицательный знак в начале, отрицательный знак в конце или круглые скобки.

    • Наличие пробела между числовым значением и символом валюты.

  • Свойство CurrencyDecimalDigits, определяющее число цифр дробной части в результирующей строке.

  • Свойство CurrencyDecimalSeparator, определяющее символ-разделитель целой и дробной частей в результирующей строке.

  • Свойство CurrencyGroupSeparator, определяющее символ-разделитель групп.

  • Свойство CurrencyGroupSizes, определяющее число цифр в каждой из групп слева от разделителя целой и дробной частей.

  • Свойство NegativeSign, задающее отрицательный знак, который используется в случаях, если скобки не применяются для обозначения отрицательных значений в результирующей строке.

Кроме того, строки числового формата могут содержать описатель точности. Смысл этого описателя зависит от строки формата, в которой он используется, но обычно он задает общее число цифр в результирующей строке или число цифр в дробной части. В следующем примере используется строка стандартного числового формата с описателем точности ("X4"), что позволяет сформировать строковое значение из четырех шестидесятеричных цифр.

Dim byteValues() As Byte = { 12, 163, 255 }
For Each byteValue As Byte In byteValues
   Console.WriteLine(byteValue.ToString("X4"))
Next
' The example displays the following output:
'       000C
'       00A3
'       00FF
byte[] byteValues = { 12, 163, 255 };
foreach (byte byteValue in byteValues)
   Console.WriteLine(byteValue.ToString("X4"));
// The example displays the following output:
//       000C
//       00A3
//       00FF

Дополнительные сведения о строках стандартных числовых форматов см. в разделе Строки стандартных числовых форматов.

Строки стандартного формата для значений даты и времени — это псевдонимы строк настраиваемого формата, которые хранятся в конкретном свойстве DateTimeFormatInfo. Например, вызов метода ToString применительно к значению даты и времени с описателем формата "D" приведет к отображению даты и времени с помощью настраиваемой строки формата, хранящейся в свойстве DateTimeFormatInfo.LongDatePattern для текущего языка и региональных параметров. (Дополнительные сведения о строках настраиваемого формата см. в следующем подразделе.) Данная связь показана в следующем примере.

Imports System.Globalization

Module Example
   Public Sub Main()
      Dim date1 As Date = #6/30/2009#
      Console.WriteLine("D Format Specifier:     {0:D}", date1)
      Dim longPattern As String = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern
      Console.WriteLine("'{0}' custom format string:     {1}", _
                        longPattern, date1.ToString(longPattern))
   End Sub
End Module
' The example displays the following output when run on a system whose
' current culture is en-US:
'    D Format Specifier:     Tuesday, June 30, 2009
'    'dddd, MMMM dd, yyyy' custom format string:     Tuesday, June 30, 2009
using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      DateTime date1 = new DateTime(2009, 6, 30);
      Console.WriteLine("D Format Specifier:     {0:D}", date1);
      string longPattern = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern;
      Console.WriteLine("'{0}' custom format string:     {1}", 
                        longPattern, date1.ToString(longPattern));
   }
}
// The example displays the following output when run on a system whose
// current culture is en-US:
//    D Format Specifier:     Tuesday, June 30, 2009
//    'dddd, MMMM dd, yyyy' custom format string:     Tuesday, June 30, 2009

Дополнительные сведения о строках стандартных форматов даты и времени см. в разделе Строки стандартных форматов даты и времени.

Строки стандартного формата также можно использовать для определения строкового представления прикладного объекта, формируемого с помощью метода ToString(String) такого объекта. Можно определить конкретные описатели стандартного формата, поддерживаемые объектом, а также решить, будут ли они зависеть от регистра символов. Реализация метода ToString(String) должна отвечать следующим условиям:

  • Должен поддерживаться описатель формата "G", отвечающий за представление обычного или общего формата объекта. Перегрузка метода ToString объекта, не имеющая параметров, должна вызывать его перегрузку ToString(String), передавая ей строку стандартного формата "G".

  • Должен поддерживаться описатель формата, равный пустой ссылке (Nothing в Visual Basic). Описатель формата, равный пустой ссылке, должен рассматриваться как эквивалент описателя формата "G".

Например, во внутреннем представлении класса Temperature температура может храниться в градусах Цельсия, а для представления значения объекта Temperature в градусах Цельсия, Фаренгейта или Кельвина могут использоваться различные описатели формата. Ниже приведен пример.

Public Class Temperature
   Private m_Temp As Decimal

   Public Sub New(temperature As Decimal)
      Me.m_Temp = temperature
   End Sub

   Public ReadOnly Property Celsius() As Decimal
      Get
         Return Me.m_Temp
      End Get   
   End Property

   Public ReadOnly Property Kelvin() As Decimal
      Get
         Return Me.m_Temp + 273.15d   
      End Get
   End Property

   Public ReadOnly Property Fahrenheit() As Decimal
      Get
         Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
      End Get      
   End Property

   Public Overrides Function ToString() As String
      Return Me.ToString("C")
   End Function

   Public Overloads Function ToString(format As String) As String  
      ' Handle null or empty string.
      If String.IsNullOrEmpty(format) Then format = "C"
      ' Remove spaces and convert to uppercase.
      format = format.Trim().ToUpperInvariant()      

      ' Convert temperature to Fahrenheit and return string.
      Select Case format
         Case "F"
            Return Me.Fahrenheit.ToString("N2") & " °F"
         ' Convert temperature to Kelvin and return string.
         Case "K"
            Return Me.Kelvin.ToString("N2") & " K"
         ' Return temperature in Celsius.
         Case "C"
            Return Me.Celsius.ToString("N2") & " °C"
         Case Else
            Throw New FormatException(String.Format("The '{0}' format string is not supported.", format))
      End Select      
   End Function
End Class

Public Module Example
   Public Sub Main()
      Dim temp1 As New Temperature(0d)
      Console.WriteLine(temp1.ToString())
      Console.WriteLine(temp1.ToString("C"))
      Console.WriteLine(temp1.ToString("F"))
      Console.WriteLine(temp1.ToString("K"))
      Dim temp2 As New Temperature(-40d)
      Console.WriteLine(temp2.ToString())
      Console.WriteLine(temp2.ToString("C"))
      Console.WriteLine(temp2.ToString("F"))
      Console.WriteLine(temp2.ToString("K"))
      Dim temp3 As New Temperature(16d)
      Console.WriteLine(temp3.ToString())
      Console.WriteLine(temp3.ToString("C"))
      Console.WriteLine(temp3.ToString("F"))
      Console.WriteLine(temp3.ToString("K"))

      Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3))
   End Sub
End Module
' The example displays the following output:
'       0.00 °C
'       0.00 °C
'       32.00 °F
'       273.15 K
'       -40.00 °C
'       -40.00 °C
'       -40.00 °F
'       233.15 K
'       16.00 °C
'       16.00 °C
'       60.80 °F
'       289.15 K
'       The temperature is now 16.00 °C.
public class Temperature
{
   private decimal m_Temp;

   public Temperature(decimal temperature)
   {
      this.m_Temp = temperature;
   }

   public decimal Celsius
   {
      get { return this.m_Temp; }
   }

   public decimal Kelvin
   {
      get { return this.m_Temp + 273.15m; }   
   }

   public decimal Fahrenheit
   {
      get { return Math.Round(((decimal) (this.m_Temp * 9 / 5 + 32)), 2); }
   }

   public override string ToString()
   {
      return this.ToString("C");
   }

   public string ToString(string format)
   {  
      // Handle null or empty string.
      if (String.IsNullOrEmpty(format)) format = "C";
      // Remove spaces and convert to uppercase.
      format = format.Trim().ToUpperInvariant();      

      // Convert temperature to Fahrenheit and return string.
      switch (format)
      {
         // Convert temperature to Fahrenheit and return string.
         case "F":
            return this.Fahrenheit.ToString("N2") + " °F";
         // Convert temperature to Kelvin and return string.
         case "K":
            return this.Kelvin.ToString("N2") + " K";
         // return temperature in Celsius.
         case "C":
            return this.Celsius.ToString("N2") + " °C";
         default:
            throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
      }      
   }
}

public class Example
{
   public static void Main()
   {
      Temperature temp1 = new Temperature(0m);
      Console.WriteLine(temp1.ToString());
      Console.WriteLine(temp1.ToString("C"));
      Console.WriteLine(temp1.ToString("F"));
      Console.WriteLine(temp1.ToString("K"));
      Temperature temp2 = new Temperature(-40m);
      Console.WriteLine(temp2.ToString());
      Console.WriteLine(temp2.ToString("C"));
      Console.WriteLine(temp2.ToString("F"));
      Console.WriteLine(temp2.ToString("K"));
      Temperature temp3 = new Temperature(16m);
      Console.WriteLine(temp3.ToString());
      Console.WriteLine(temp3.ToString("C"));
      Console.WriteLine(temp3.ToString("F"));
      Console.WriteLine(temp3.ToString("K"));

      Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3));
   }
}
// The example displays the following output:
//       0.00 °C
//       0.00 °C
//       32.00 °F
//       273.15 K
//       -40.00 °C
//       -40.00 °C
//       -40.00 °F
//       233.15 K
//       16.00 °C
//       16.00 °C
//       60.80 °F
//       289.15 K
//       The temperature is now 16.00 °C.

К началу

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

Помимо строк стандартного формата, в платформе .NET Framework для числовых значений и значений даты и времени определяются строки настраиваемого формата. Строка настраиваемого формата состоит из одного или нескольких описателей настраиваемого формата, описывающих строковое представление значения. Например, строка настраиваемого формата даты и времени, заданная как "yyyy/mm/dd hh:mm:ss.ffff t zzz", преобразует дату в строковое представления вида "2008/11/15 07:45:00.0000 P -08:00" для языка и региональных параметров "en-US". Аналогично строка настраиваемого формата "0000" приведет к преобразованию целочисленного значения 12 в строку "0012". Полный список строк настраиваемого формата см. в разделах Строки настраиваемых форматов даты и времени и Строки настраиваемых числовых форматов.

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

Dim date1 As Date = #09/08/2009#
Console.WriteLine(date1.ToString("%M"))      ' Displays 9
DateTime date1 = new DateTime(2009, 9, 8);
Console.WriteLine(date1.ToString("%M"));       // Displays 9

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

Dim customFormat As String = "MMMM dd, yyyy (dddd)"
Dim date1 As Date = #8/28/2009#
Console.WriteLine(date1.ToString(customFormat))   
' The example displays the following output if run on a system
' whose language is English:
'       August 28, 2009 (Friday)      
string customFormat = "MMMM dd, yyyy (dddd)";
DateTime date1 = new DateTime(2009, 8, 28);
Console.WriteLine(date1.ToString(customFormat));   
// The example displays the following output if run on a system
// whose language is English:
//       August 28, 2009 (Friday)      

Хотя строк стандартного формата обычно достаточно для выполнения большинства задач форматирования прикладных типов, для форматирования пользовательских типов также можно определять описатели настраиваемого формата.

К началу

Поставщики форматирования и интерфейс IFormatProvider

Хотя описатели формата позволяют настраивать форматирование объектов, для формирования осмысленного строкового представления объектов зачастую требуется дополнительная информация, связанная с форматированием. Например, при форматировании числового значения в формате валюты с помощью строки стандартного формата "C" или строки настраиваемого формата "$ #,#.00" для включения в отформатированную строку должен быть известен нужный символ валюты, разделитель групп, а также разделитель целой и дробной частей. В платформе .NET Framework подобные дополнительные сведения предоставляются с помощью интерфейса IFormatProvider, передаваемого в качестве параметра одной или нескольких перегрузок метода ToString для числовых типов и типов даты и времени. В следующем примере показано, как меняется строковое представление объекта, когда он форматируется с помощью трех разных объектов IFormatProvider.

Imports System.Globalization

Public Module Example
   Public Sub Main()
      Dim value As Decimal = 1603.42d
      Console.WriteLine(value.ToString("C3", New CultureInfo("en-US")))
      Console.WriteLine(value.ToString("C3", New CultureInfo("fr-FR")))
      Console.WriteLine(value.ToString("C3", New CultureInfo("de-DE")))
   End Sub
End Module
' The example displays the following output:
'       $1,603.420
'       1 603,420 €
'       1.603,420 €
using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      decimal value = 1603.42m;
      Console.WriteLine(value.ToString("C3", new CultureInfo("en-US")));
      Console.WriteLine(value.ToString("C3", new CultureInfo("fr-FR")));
      Console.WriteLine(value.ToString("C3", new CultureInfo("de-DE")));
   }
}
// The example displays the following output:
//       $1,603.420
//       1 603,420 €
//       1.603,420 €

Интерфейс IFormatProvider включает один метод, GetFormat(Type), имеющий один параметр, задающий тип объекта, предоставляющего сведения о форматировании. Если метод может предоставить объект указанного типа, то он его возвращает. В противном случае метод возвратит пустую ссылку (Nothing в Visual Basic).

Метод IFormatProvider.GetFormat является методом обратного вызова. При вызове перегрузки метода ToString, имеющей параметр IFormatProvider, вызывается метод GetFormat соответствующего объекта IFormatProvider. Метод GetFormat должен вернуть в метод ToString объект, способный предоставить необходимые сведения о форматировании и соответствующий параметру formatType.

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

Метод

Тип параметра formatType

Метод ToString для числовых типов

System.Globalization.NumberFormatInfo

Метод ToString для типов даты и времени

System.Globalization.DateTimeFormatInfo

String.Format

System.ICustomFormatter

StringBuilder.AppendFormat

System.ICustomFormatter

ПримечаниеПримечание

Методы ToString у числовых типов и типов даты и времени перегружены; параметр IFormatProvider имеется лишь у некоторых перегрузок.Если у метода нет параметра типа IFormatProvider, то вместо этого передается объект, возвращаемый свойством CultureInfo.CurrentCulture.Например, вызов метода Int32.ToString() по умолчанию в итоге приведет к подобному вызову метода: Int32.ToString("G", System.Globalization.CultureInfo.CurrentCulture).

В составе платформы .NET Framework есть три класса, реализующих интерфейс IFormatProvider.

  • DateTimeFormatInfo: класс, предоставляющий сведения о форматировании значений даты и времени для конкретного языка и региональных параметров. Реализация метода IFormatProvider.GetFormat в этом классе возвращает его экземпляр.

  • NumberFormatInfo: класс, предоставляющий сведения о форматировании числовых значений для конкретного языка и региональных параметров. Реализация метода IFormatProvider.GetFormat в этом классе возвращает его экземпляр.

  • CultureInfo. Реализация метода IFormatProvider.GetFormat в этом классе возвращает объект NumberFormatInfo, предоставляющий сведения о форматировании числовых значений, либо объект DateTimeFormatInfo, предоставляющий сведения о форматировании значений даты и времени.

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

К началу

Интерфейс IFormattable

Обычно типы, в которых имеется перегрузка метода ToString, использующая строку формата и параметр IFormatProvider, также реализуют интерфейс IFormattable. Единственный член этого интерфейса — метод IFormattable.ToString(String, IFormatProvider), параметрами которого являются строка формата и поставщик форматирования.

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

  • Поддержка строковых преобразований с помощью класса Convert. При вызове методов Convert.ToString(Object) и Convert.ToString(Object, IFormatProvider) автоматически вызывается пользовательская реализация IFormattable.

  • Поддержка составного форматирования. Если для форматирования пользовательского типа используется элемент форматирования, включающий строку формата, то среда CLR автоматически вызывает пользовательскую реализацию IFormattable, передавая ей строку формата. Дополнительные сведения о составном форматировании с помощью таких методов, как String.Format или Console.WriteLine, см. в подразделе Составное форматирование.

В следующем примере определяется класс Temperature, реализующий интерфейс IFormattable. Он поддерживает описатели формата "C" и "G", позволяющие отобразить значение температуры в градусах Цельсия, описатель формата "F", позволяющий отобразить значение температуры в градусах Фаренгейта, и описатель формата "K", позволяющий отобразить значение температуры в градусах Кельвина.

Imports System.Globalization

Public Class Temperature : Implements IFormattable
   Private m_Temp As Decimal

   Public Sub New(temperature As Decimal)
      Me.m_Temp = temperature
   End Sub

   Public ReadOnly Property Celsius() As Decimal
      Get
         Return Me.m_Temp
      End Get   
   End Property

   Public ReadOnly Property Kelvin() As Decimal
      Get
         Return Me.m_Temp + 273.15d   
      End Get
   End Property

   Public ReadOnly Property Fahrenheit() As Decimal
      Get
         Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
      End Get      
   End Property

   Public Overrides Function ToString() As String
      Return Me.ToString("G", Nothing)
   End Function

   Public Overloads Function ToString(format As String) As String
      Return Me.ToString(format, Nothing)
   End Function

   Public Overloads Function ToString(format As String, provider As IFormatProvider) As String _  
      Implements IFormattable.ToString

      ' Handle null or empty arguments.
      If String.IsNullOrEmpty(format) Then format = "G"
      ' Remove any white space and convert to uppercase.
      format = format.Trim().ToUpperInvariant()

      If provider Is Nothing Then provider = NumberFormatInfo.CurrentInfo

      Select Case format
         ' Convert temperature to Fahrenheit and return string.
         Case "F"
            Return Me.Fahrenheit.ToString("N2", provider) & "°F"
         ' Convert temperature to Kelvin and return string.
         Case "K"
            Return Me.Kelvin.ToString("N2", provider) & "K"
         ' Return temperature in Celsius.
         Case "C", "G"
            Return Me.Celsius.ToString("N2", provider) & "°C"
         Case Else
            Throw New FormatException(String.Format("The '{0}' format string is not supported.", format))
      End Select      
   End Function
End Class
using System;
using System.Globalization;

public class Temperature : IFormattable
{
   private decimal m_Temp;

   public Temperature(decimal temperature)
   {
      this.m_Temp = temperature;
   }

   public decimal Celsius
   {
      get { return this.m_Temp; }
   }

   public decimal Kelvin
   {
      get { return this.m_Temp + 273.15m; }   
   }

   public decimal Fahrenheit
   {
      get { return Math.Round((decimal) this.m_Temp * 9 / 5 + 32, 2); }
   }

   public override string ToString()
   {
      return this.ToString("G", null);
   }

   public string ToString(string format)
   {
      return this.ToString(format, null);
   }

   public string ToString(string format, IFormatProvider provider)  
   {
      // Handle null or empty arguments.
      if (String.IsNullOrEmpty(format)) format = "G";
      // Remove any white space and convert to uppercase.
      format = format.Trim().ToUpperInvariant();

      if (provider == null) provider = NumberFormatInfo.CurrentInfo;

      switch (format)
      {
         // Convert temperature to Fahrenheit and return string.
         case "F":
            return this.Fahrenheit.ToString("N2", provider) + "°F";
         // Convert temperature to Kelvin and return string.
         case "K":
            return this.Kelvin.ToString("N2", provider) + "K";
         // Return temperature in Celsius.
         case "C":
         case "G":
            return this.Celsius.ToString("N2", provider) + "°C";
         default:
            throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
      }      
   }
}

В следующем примере создается объект Temperature. Затем в нем вызывается метод ToString. Использование нескольких строк составного формата позволяет получить различные строковые представления объекта Temperature. В свою очередь каждый из этих вызовов метода вызывает реализацию IFormattable класса Temperature.

Public Module Example
   Public Sub Main()
      Dim temp1 As New Temperature(22d)
      Console.WriteLine(Convert.ToString(temp1, New CultureInfo("ja-JP")))
      Console.WriteLine("Temperature: {0:K}", temp1)
      Console.WriteLine("Temperature: {0:F}", temp1)
      Console.WriteLine(String.Format(New CultureInfo("fr-FR"), "Temperature: {0:F}", temp1)) 
   End Sub
End Module
' The example displays the following output:
'       22.00°C
'       Temperature: 295.15°K
'       Temperature: 71.60°F
'       Temperature: 71,60°F
public class Example
{
   public static void Main()
   {
      Temperature temp1 = new Temperature(22m);
      Console.WriteLine(Convert.ToString(temp1, new CultureInfo("ja-JP")));
      Console.WriteLine("Temperature: {0:K}", temp1);
      Console.WriteLine("Temperature: {0:F}", temp1);
      Console.WriteLine(String.Format(new CultureInfo("fr-FR"), "Temperature: {0:F}", temp1));
   }
}
// The example displays the following output:
//       22.00°C
//       Temperature: 295.15°K
//       Temperature: 71.60°F
//       Temperature: 71,60°F

К началу

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

Некоторые методы, например String.Format и StringBuilder.AppendFormat, поддерживают составное форматирование. Строка составного формата — это некий шаблон, возвращающий единую строку, включающую строковое представление нулевого, единичного или другого числа объектов. Каждый объект представляется в строке составного формата индексированным элементом форматирования. Индекс элемента форматирования соответствует положению представляющего его объекта в списке параметров метода. Индексы отсчитываются от нуля. Например, в вызове метода String.Format первый элемент форматирования, {0:D}, замещается строковым представлением thatDate; второй элемент форматирования, {1}, замещается строковым представлением item1; третий элемент форматирования, {2:C2}, замещается строковым представлением item1.Value.

result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.", _
                       thatDate, item1, item1.Value)
Console.WriteLine(result)                            
' The example displays output like the following if run on a system
' whose current culture is en-US:
'       On 5/1/2009, the inventory of WidgetA was worth $107.44.
result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.", 
                       thatDate, item1, item1.Value);
Console.WriteLine(result);                            
// The example displays output like the following if run on a system
// whose current culture is en-US:
//       On 5/1/2009, the inventory of WidgetA was worth $107.44.

Дополнительные сведения о составном форматировании см. в разделе Составное форматирование.

К началу

Настраиваемое форматирование с использованием интерфейса ICustomFormatter

У некоторых методов составного форматирования, например String.Format(IFormatProvider, String, Object>) и StringBuilder.AppendFormat(IFormatProvider, String, Object>), имеется параметр, задающий поставщик форматирования, поддерживающий настраиваемое форматирование. При вызове метода форматирования в метод GetFormat поставщика форматирования передается объект Type, представляющий интерфейс ICustomFormatter. Метод GetFormat должен вернуть реализацию ICustomFormatter, поддерживающую настраиваемое форматирование.

Единственный метод интерфейса ICustomFormatter, который называется Format(String, Object, IFormatProvider), автоматически вызывается методом составного форматирования по одному разу для каждого элемента форматирования в строке составного формата. У метода Format(String, Object, IFormatProvider) есть три параметра: строка формата, представляющая аргумент formatString в элементе форматирования, сам форматируемый объект и объект IFormatProvider, предоставляющий услуги форматирования. Обычно класс, реализующий интерфейс ICustomFormatter, также реализует интерфейс IFormatProvider, поэтому в таком случае последний параметр будет ссылкой на сам класс настраиваемого форматирования. Метод возвращает настраиваемое строковое представление объекта, который нужно было отформатировать. Если методу не удается отформатировать объект, он должен вернуть пустую ссылку (Nothing в Visual Basic).

В следующем примере приведена реализация ICustomFormatter с именем ByteByByteFormatter, отображающая целочисленные значения в виде последовательности пар шестидесятеричных цифр, разделенных пробелами.

Public Class ByteByByteFormatter : 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, arg As Object, 
                          formatProvider As IFormatProvider) As String _
                          Implements ICustomFormatter.Format

      If Not formatProvider.Equals(Me) Then Return Nothing

      ' Handle only hexadecimal format string.
      If Not fmt.StartsWith("X") Then 
            Return Nothing
      End If

      ' Handle only integral types.
      If Not typeof arg Is Byte AndAlso
         Not typeof arg Is Int16 AndAlso
         Not typeof arg Is Int32 AndAlso
         Not typeof arg Is Int64 AndAlso
         Not typeof arg Is SByte AndAlso
         Not typeof arg Is UInt16 AndAlso
         Not typeof arg Is UInt32 AndAlso
         Not typeof arg Is UInt64 Then _
            Return Nothing

      Dim bytes() As Byte = BitConverter.GetBytes(arg)
      Dim output As String = Nothing

      For ctr As Integer = bytes.Length - 1 To 0 Step -1
         output += String.Format("{0:X2} ", bytes(ctr))   
      Next

      Return output.Trim()
   End Function
End Class
public class ByteByByteFormatter : 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 (! formatProvider.Equals(this)) return null;

      // Handle only hexadecimal format string.
      if (! format.StartsWith("X")) return null;

      byte[] bytes;
      string output = null;

      // Handle only integral types.
      if (arg is Byte) 
         bytes = BitConverter.GetBytes((Byte) arg);
      else if (arg is Int16)
         bytes = BitConverter.GetBytes((Int16) arg);
      else if (arg is Int32)
         bytes = BitConverter.GetBytes((Int32) arg);
      else if (arg is Int64)   
         bytes = BitConverter.GetBytes((Int64) arg);
      else if (arg is SByte)
         bytes = BitConverter.GetBytes((SByte) arg);
      else if (arg is UInt16)
         bytes = BitConverter.GetBytes((UInt16) arg);
      else if (arg is UInt32)
         bytes = BitConverter.GetBytes((UInt32) arg);
      else if (arg is UInt64)
         bytes = BitConverter.GetBytes((UInt64) arg);
      else
         return null;

      for (int ctr = bytes.Length - 1; ctr >= 0; ctr--)
         output += String.Format("{0:X2} ", bytes[ctr]);   

      return output.Trim();
   }
}

В следующем примере класс ByteByByteFormatter используется для форматирования целочисленных значений. Обратите внимание, что метод ICustomFormatter.Format вызывается во втором вызове метода String.Format(IFormatProvider, String, Object>) несколько раз и что в третьем вызове метода используется поставщик NumberFormatInfo по умолчанию, поскольку метод ByteByByteFormatter.Format не распознает строку формата "N0" и возвращает пустую ссылку (Nothing в Visual Basic).

Public Module Example
   Public Sub Main()
      Dim value As Long = 3210662321 
      Dim value1 As Byte = 214
      Dim value2 As Byte = 19

      Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X}", value)))
      Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})", 
                                      value1, value2, value1 And value2)))                                
      Console.WriteLine(String.Format(New ByteByByteFormatter(), "{0,10:N0}", value))
   End Sub
End Module
' The example displays the following output:
'       00 00 00 00 BF 5E D1 B1
'       00 D6 And 00 13 = 00 12 (018)
'       3,210,662,321
public class Example
{
   public static void Main()
   {
      long value = 3210662321; 
      byte value1 = 214;
      byte value2 = 19;

      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X}", value));
      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})", 
                                      value1, value2, value1 & value2));                                
      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0,10:N0}", value));
   }
}
// The example displays the following output:
//       00 00 00 00 BF 5E D1 B1
//       00 D6 And 00 13 = 00 12 (018)
//       3,210,662,321

К началу

Связанные разделы

Заголовок

Определение

Строки стандартных числовых форматов

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

Строки настраиваемых числовых форматов

Описание строк настраиваемого формата, позволяющих создавать прикладные строковые представления числовых значений.

Строки стандартных форматов даты и времени

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

Строки настраиваемых форматов даты и времени

Описание строк настраиваемого формата, позволяющих создавать прикладные строковые представления значений DateTime.

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

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

Строки пользовательского формата TimeSpan

Описание строк настраиваемого формата, позволяющих создавать прикладные строковые представления интервалов времени.

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

Описание строк стандартного формата, используемых для создания строковых представлений значений перечислений.

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

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

Выполнение операций форматирования

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

Разбор строк

Описание способов инициализации объектов со значениями, описанными строковыми представлениями этих объектов. Разбор является операцией, обратной форматированию.

К началу

Ссылки

System.IFormattable

System.IFormatProvider

System.ICustomFormatter