Практическое руководство. Определение и использование поставщиков настраиваемых числовых форматовHow to: Define and Use Custom Numeric Format Providers

.NET Framework обеспечивает расширенный контроль над строковым представлением числовых значений.The .NET Framework gives you extensive control over the string representation of numeric values. Эта платформа поддерживает указанные далее возможности для настройки форматов числовых значений.It supports the following features for customizing the format of numeric values:

  • Строки стандартных числовых форматов, которые предоставляют стандартный набор форматов для преобразования чисел в их строковое представление.Standard numeric format strings, which provide a predefined set of formats for converting numbers to their string representation. Вы можете использовать их с любым методом числового форматирования, например Decimal.ToString(String) с параметром format.You can use them with any numeric formatting method, such as Decimal.ToString(String), that has a format parameter. Дополнительные сведения см. в статье Строки стандартных числовых форматов.For details, see Standard Numeric Format Strings.

  • Строки настраиваемых числовых форматов, предоставляющих набор символов, которые могут быть объединены для определения описателей настраиваемого числового формата.Custom numeric format strings, which provide a set of symbols that can be combined to define custom numeric format specifiers. Их можно использовать с любым методом числового форматирования, например Decimal.ToString(String) с параметром format.They can also be used with any numeric formatting method, such as Decimal.ToString(String), that has a format parameter. Дополнительные сведения см. в разделе Строки настраиваемых числовых форматов.For details, see Custom Numeric Format Strings.

  • Настраиваемые объекты CultureInfo и NumberFormatInfo, которые определяют символы и шаблоны форматирования для отображения строковых представлений числовых значений.Custom CultureInfo or NumberFormatInfo objects, which define the symbols and format patterns used in displaying the string representations of numeric values. Вы можете использовать их с любым методом числового форматирования, например ToString с параметром provider.You can use them with any numeric formatting method, such as ToString, that has a provider parameter. Как правило, параметр provider используется для указания форматирования, зависящего от языка и региональных параметров.Typically, the provider parameter is used to specify culture-specific formatting.

В некоторых случаях (например, когда приложению необходимо отобразить отформатированный номер учетной записи, идентификационный номер или почтовый индекс) эти три метода неприменимы.In some cases (such as when an application must display a formatted account number, an identification number, or a postal code) these three techniques are inappropriate. Также .NET Framework позволяет определить объект форматирования, который не является объектом CultureInfo или NumberFormatInfo, для определения порядка форматирования числовых значений.The .NET Framework also enables you to define a formatting object that is neither a CultureInfo nor a NumberFormatInfo object to determine how a numeric value is formatted. Этот раздел содержит пошаговые инструкции по реализации таких объектов и пример форматирования телефонных номеров.This topic provides the step-by-step instructions for implementing such an object, and provides an example that formats telephone numbers.

Определение поставщика пользовательского форматаTo define a custom format provider

  1. Определите класс, реализующий интерфейсы IFormatProvider и ICustomFormatter.Define a class that implements the IFormatProvider and ICustomFormatter interfaces.

  2. Выполните метод IFormatProvider.GetFormat.Implement the IFormatProvider.GetFormat method. GetFormat — это метод обратного вызова, с помощью которого метод форматирования (например, String.Format(IFormatProvider, String, Object[])) вызывает объект, отвечающий за выполнение пользовательского форматирования.GetFormat is a callback method that the formatting method (such as the String.Format(IFormatProvider, String, Object[]) method) invokes to retrieve the object that is actually responsible for performing custom formatting. Метод GetFormat в типичной реализации выполняет следующие действия:A typical implementation of GetFormat does the following:

    1. Определяет, предоставляет ли объект Type, полученный в качестве параметра, интерфейс ICustomFormatter.Determines whether the Type object passed as a method parameter represents an ICustomFormatter interface.

    2. Если параметр представляет интерфейс ICustomFormatter, то метод GetFormat возвращает объект, реализующий интерфейс ICustomFormatter, который отвечает за применение пользовательского форматирования.If the parameter does represent the ICustomFormatter interface, GetFormat returns an object that implements the ICustomFormatter interface that is responsible for providing custom formatting. Как правило, объект пользовательского форматирования возвращает сам себя.Typically, the custom formatting object returns itself.

    3. Если параметр не представляет интерфейс ICustomFormatter, GetFormat возвращает null.If the parameter does not represent the ICustomFormatter interface, GetFormat returns null.

  3. Выполните метод Format.Implement the Format method. Этот метод вызывается из метода String.Format(IFormatProvider, String, Object[]) и возвращает строковое представление числа.This method is called by the String.Format(IFormatProvider, String, Object[]) method and is responsible for returning the string representation of a number. Реализация этого метода обычно включает в себя выполнение следующих действий.Implementing the method typically involves the following:

    1. Вы можете проверить параметр provider, чтобы убедиться, что метод действительно предназначен для форматирования.Optionally, make sure that the method is legitimately intended to provide formatting services by examining the provider parameter. Для объектов форматирования, которые реализуют интерфейсы IFormatProvider и ICustomFormatter, нужно проверить еще и параметр provider, значение которого должно совпадать с текущим объектом форматирования.For formatting objects that implement both IFormatProvider and ICustomFormatter, this involves testing the provider parameter for equality with the current formatting object.

    2. Определите, должен ли объект форматирования поддерживать описатели настраиваемого формата.Determine whether the formatting object should support custom format specifiers. (Например, описатель формата "N" может указывать, что телефонный номер США следует выводить в формате NANP, а "I" может означать вывод в формате E.123 в соответствии с рекомендацией ITU-T.) Если используются описатели формата, то метод должен обрабатывать этот описатель определенного формата.(For example, an "N" format specifier might indicate that a U.S. telephone number should be output in NANP format, and an "I" might indicate output in ITU-T Recommendation E.123 format.) If format specifiers are used, the method should handle the specific format specifier. Он передается методу в параметре format.It is passed to the method in the format parameter. Если описатель отсутствует, значением параметра format является String.Empty.If no specifier is present, the value of the format parameter is String.Empty.

    3. Получите числовое значение, передаваемое методу в параметре arg.Retrieve the numeric value passed to the method as the arg parameter. Выполните операции, необходимые для его преобразования в строковое представление.Perform whatever manipulations are required to convert it to its string representation.

    4. Верните строковое представление параметра arg.Return the string representation of the arg parameter.

Использование объекта настраиваемого числового форматированияTo use a custom numeric formatting object

  1. Создайте новый экземпляр класса настраиваемого форматирования.Create a new instance of the custom formatting class.

  2. Вызовите метод форматирования String.Format(IFormatProvider, String, Object[]), передав ему объект пользовательского форматирования, описатель форматирования (или String.Empty, если описатель не используется) и числовое значение для форматирования.Call the String.Format(IFormatProvider, String, Object[]) formatting method, passing it the custom formatting object, the formatting specifier (or String.Empty, if one is not used), and the numeric value to be formatted.

ПримерExample

В следующем примере определяется поставщик настраиваемого числового формата с именем TelephoneFormatter, который преобразует число, представляющее номер телефона в США, в формат NANP или E.123.The following example defines a custom numeric format provider named TelephoneFormatter that converts a number that represents a U.S. telephone number to its NANP or E.123 format. Метод обрабатывает два описателя формата "N" (вывод в формате NANP) и "I" (вывод в международном формате E.123).The method handles two format specifiers, "N" (which outputs the NANP format) and "I" (which outputs the international E.123 format).

using System;
using System.Globalization;

public class TelephoneFormatter : 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)
   {
      // Check whether this is an appropriate callback             
      if (! this.Equals(formatProvider))
         return null; 

      // Set default format specifier             
      if (string.IsNullOrEmpty(format)) 
         format = "N";

      string numericString = arg.ToString();
      
      if (format == "N")
      {
         if (numericString.Length <= 4)
            return numericString;
         else if (numericString.Length == 7)
            return numericString.Substring(0, 3) + "-" + numericString.Substring(3, 4); 
         else if (numericString.Length == 10)
               return "(" + numericString.Substring(0, 3) + ") " +
                      numericString.Substring(3, 3) + "-" + numericString.Substring(6);   
         else
            throw new FormatException( 
                      string.Format("'{0}' cannot be used to format {1}.", 
                                    format, arg.ToString()));
      }
      else if (format == "I")
      {
         if (numericString.Length < 10)
            throw new FormatException(string.Format("{0} does not have 10 digits.", arg.ToString()));
         else
            numericString = "+1 " + numericString.Substring(0, 3) + " " + numericString.Substring(3, 3) + " " + numericString.Substring(6);
      }
      else
      {
         throw new FormatException(string.Format("The {0} format specifier is invalid.", format));
      } 
      return numericString;  
   }
}

public class TestTelephoneFormatter
{
   public static void Main()
   {
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 0));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 911));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 8490216));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));
      
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 0));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 911));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 8490216));
      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));

      Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:I}", 4257884748));
   }
}
Public Class TelephoneFormatter : 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
      ' Check whether this is an appropriate callback             
      If Not Me.Equals(formatProvider) Then Return Nothing 

      ' Set default format specifier             
      If String.IsNullOrEmpty(fmt) Then fmt = "N"

      Dim numericString As String = arg.ToString
      
      If fmt = "N" Then
         Select Case numericString.Length
            Case <= 4 
               Return numericString
            Case 7
               Return Left(numericString, 3) & "-" & Mid(numericString, 4) 
            Case 10
               Return "(" & Left(numericString, 3) & ") " & _
                      Mid(numericString, 4, 3) & "-" & Mid(numericString, 7)   
            Case Else
               Throw New FormatException( _
                         String.Format("'{0}' cannot be used to format {1}.", _
                                       fmt, arg.ToString()))
         End Select
      ElseIf fmt = "I" Then
         If numericString.Length < 10 Then
            Throw New FormatException(String.Format("{0} does not have 10 digits.", arg.ToString()))
         Else
            numericString = "+1 " & Left(numericString, 3) & " " & Mid(numericString, 4, 3) & " " & Mid(numericString, 7)
         End If      
      Else
         Throw New FormatException(String.Format("The {0} format specifier is invalid.", fmt))
      End If 
      Return numericString  
   End Function
End Class

Public Module TestTelephoneFormatter
   Public Sub Main
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 0))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 911))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 8490216))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))
      
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 0))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 911))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 8490216))
      Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))

      Console.WriteLine(String.Format(New TelephoneFormatter, "{0:I}", 4257884748))
   End Sub
End Module

Поставщик настраиваемого числового формата можно использовать только с методом String.Format(IFormatProvider, String, Object[]).The custom numeric format provider can be used only with the String.Format(IFormatProvider, String, Object[]) method. Другие перегрузки методов числового форматирования (например, ToString), у которых параметр имеет тип IFormatProvider, передают в реализацию метода IFormatProvider.GetFormat объект Type, представляющий тип NumberFormatInfo.The other overloads of numeric formatting methods (such as ToString) that have a parameter of type IFormatProvider all pass the IFormatProvider.GetFormat implementation a Type object that represents the NumberFormatInfo type. В ответ они ожидают получить объект NumberFormatInfo.In return, they expect the method to return a NumberFormatInfo object. Если это не так, поставщик настраиваемого числового формата игнорируется, и вместо него используется объект NumberFormatInfo для текущих языка и региональных параметров.If it does not, the custom numeric format provider is ignored, and the NumberFormatInfo object for the current culture is used in its place. В нашем примере метод TelephoneFormatter.GetFormat обрабатывает случай некорректной передачи его в метод числового форматирования. Для этого он проверяет параметр метода и возвращает null, если его тип отличается от ICustomFormatter.In the example, the TelephoneFormatter.GetFormat method handles the possibility that it may be inappropriately passed to a numeric formatting method by examining the method parameter and returning null if it represents a type other than ICustomFormatter.

Если поставщик настраиваемого числового формата поддерживает набор описателей формата, обязательно предоставьте поведение по умолчанию на случай, если описатель формата не указан в элементе форматирования при вызове метода String.Format(IFormatProvider, String, Object[]).If a custom numeric format provider supports a set of format specifiers, make sure you provide a default behavior if no format specifier is supplied in the format item used in the String.Format(IFormatProvider, String, Object[]) method call. В приведенном примере "N" является описателем формата по умолчанию.In the example, "N" is the default format specifier. Это позволяет преобразовать число в формат телефонного номера, явно предоставляя описатель формата.This allows for a number to be converted to a formatted telephone number by providing an explicit format specifier. В следующем примере показан такой вызов метода.The following example illustrates such a method call.

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))

Но это также позволяет выполнить преобразование в случае, если описатель формата отсутствует.But it also allows the conversion to occur if no format specifier is present. В следующем примере показан такой вызов метода.The following example illustrates such a method call.

Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))

Если описатель формата по умолчанию не определен, реализация метода ICustomFormatter.Format должна содержать код, аналогичный приведенному ниже, чтобы платформа .NET предоставила не поддерживаемое в коде форматирование.If no default format specifier is defined, your implementation of the ICustomFormatter.Format method should include code such as the following so that .NET can provide formatting that your code does not support.

if (arg is IFormattable) 
   s = ((IFormattable)arg).ToString(format, formatProvider);
else if (arg != null)    
   s = arg.ToString();
If TypeOf(arg) Is IFormattable Then 
   s = DirectCast(arg, IFormattable).ToString(fmt, formatProvider)
ElseIf arg IsNot Nothing Then    
   s = arg.ToString()
End If

В нашем примере метод, который реализует ICustomFormatter.Format, будет использоваться как метод обратного вызова для метода String.Format(IFormatProvider, String, Object[]).In the case of this example, the method that implements ICustomFormatter.Format is intended to serve as a callback method for the String.Format(IFormatProvider, String, Object[]) method. Это значит, что он должен проверить параметр formatProvider на наличие ссылки на текущий объект TelephoneFormatter.Therefore, it examines the formatProvider parameter to determine whether it contains a reference to the current TelephoneFormatter object. Тем не менее, метод можно также вызвать непосредственно из кода.However, the method can also be called directly from code. В этом случае вы можете использовать параметр formatProvider для предоставления объекта CultureInfo или NumberFormatInfo со сведениями о форматировании для выбранного языка и региональных параметров.In that case, you can use the formatProvider parameter to provide a CultureInfo or NumberFormatInfo object that supplies culture-specific formatting information.

См. такжеSee also