Instrukcje: Definiowanie i używanie niestandardowych dostawców formatu liczbowego

Platforma .NET zapewnia obszerną kontrolę nad reprezentacją ciągu wartości liczbowych. Obsługuje ona następujące funkcje dostosowywania formatu wartości liczbowych:

  • Standardowe ciągi formatu liczbowego, które zapewniają wstępnie zdefiniowany zestaw formatów do konwertowania liczb na ich reprezentację ciągów. Można ich używać z dowolną metodą formatowania liczbowego, taką jak Decimal.ToString(String), z parametrem format . Aby uzyskać szczegółowe informacje, zobacz Standardowe ciągi formatu liczbowego.

  • Niestandardowe ciągi formatu liczbowego, które zapewniają zestaw symboli, które można połączyć w celu zdefiniowania niestandardowych specyfikatorów formatu liczbowego. Mogą być one również używane z dowolną metodą formatowania liczbowego, taką jak Decimal.ToString(String), z parametrem format . Aby uzyskać szczegółowe informacje, zobacz Niestandardowe ciągi formatu liczbowego.

  • Niestandardowe CultureInfo lub NumberFormatInfo obiekty, które definiują symbole i wzorce formatu używane w wyświetlaniu reprezentacji ciągów wartości liczbowych. Można ich używać z dowolną metodą formatowania liczbowego, taką jak ToString, z parametrem provider . Zazwyczaj parametr służy do określania provider formatowania specyficznego dla kultury.

W niektórych przypadkach (na przykład gdy aplikacja musi wyświetlić sformatowany numer konta, numer identyfikacyjny lub kod pocztowy) te trzy techniki są nieodpowiednie. Platforma .NET umożliwia również zdefiniowanie obiektu formatowania, który nie jest ani obiektem CultureInfoNumberFormatInfo , aby określić sposób formatowania wartości liczbowej. Ten temat zawiera instrukcje krok po kroku dotyczące implementowania takiego obiektu oraz przykład formatowania numerów telefonów.

Definiowanie niestandardowego dostawcy formatu

  1. Zdefiniuj klasę, która implementuje IFormatProvider interfejsy i ICustomFormatter .

  2. Zaimplementuj metodę IFormatProvider.GetFormat . GetFormat to metoda wywołania zwrotnego wywoływana przez metodę formatowania (na String.Format(IFormatProvider, String, Object[]) przykład metodę) w celu pobrania obiektu, który jest faktycznie odpowiedzialny za wykonywanie niestandardowego formatowania. Typowa implementacja GetFormat wykonuje następujące czynności:

    1. Określa, czy Type obiekt przekazany jako parametr metody reprezentuje ICustomFormatter interfejs.

    2. Jeśli parametr reprezentuje ICustomFormatter interfejs, GetFormat zwraca obiekt, który implementuje ICustomFormatter interfejs odpowiedzialny za zapewnienie niestandardowego formatowania. Zazwyczaj obiekt formatowania niestandardowego zwraca się sam.

    3. Jeśli parametr nie reprezentuje interfejsu ICustomFormatter , GetFormat zwraca wartość null.

  3. Zaimplementuj metodę Format . Ta metoda jest wywoływana przez metodę String.Format(IFormatProvider, String, Object[]) i jest odpowiedzialna za zwracanie reprezentacji ciągu liczby. Implementacja metody zwykle obejmuje następujące elementy:

    1. Opcjonalnie upewnij się, że metoda jest prawidłowo przeznaczona do świadczenia usług formatowania, sprawdzając provider parametr . W przypadku obiektów formatowania, które implementują obiekty IFormatProvider i ICustomFormatter, obejmuje to przetestowanie parametru provider pod kątem równości z bieżącym obiektem formatowania.

    2. Określ, czy obiekt formatowania powinien obsługiwać specyfikatory formatu niestandardowego. (Na przykład specyfikator formatu "N" może wskazywać, że numer telefonu USA powinien być wyjściowy w formacie NANP, a "I" może wskazywać dane wyjściowe w formacie ITU-T Rekomendacja E.123). Jeśli są używane specyfikatory formatu, metoda powinna obsługiwać specyfikator określonego formatu. Jest on przekazywany do metody w parametrze format . Jeśli nie ma specyfikatora, wartość parametru format to String.Empty.

    3. Pobierz wartość liczbową przekazaną do metody jako parametr.arg Wykonaj wszelkie manipulacje, aby przekonwertować je na reprezentację ciągu.

    4. Zwróć reprezentację ciągu parametru arg .

Używanie niestandardowego obiektu formatowania liczbowego

  1. Utwórz nowe wystąpienie niestandardowej klasy formatowania.

  2. Wywołaj metodę String.Format(IFormatProvider, String, Object[]) formatowania, przekazując obiekt formatowania niestandardowego, specyfikator formatowania (lub String.Empty, jeśli nie jest używany), oraz wartość liczbową do sformatowania.

Przykład

W poniższym przykładzie zdefiniowano niestandardowego dostawcę formatu liczbowego o nazwie TelephoneFormatter , który konwertuje liczbę reprezentującą numer telefonu USA na format NANP lub E.123. Metoda obsługuje dwa specyfikatory formatu: "N" (który generuje format NANP) i "I" (który generuje międzynarodowy format E.123).

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

Niestandardowy dostawca formatu liczbowego może być używany tylko z String.Format(IFormatProvider, String, Object[]) metodą . Inne przeciążenia metod formatowania liczbowego (takich jak ToString) z parametrem typu IFormatProvider wszystkie przekazują implementację IFormatProvider.GetFormatType obiektu, który reprezentuje NumberFormatInfo typ. W zamian oczekują, że metoda zwróci NumberFormatInfo obiekt. Jeśli tak nie jest, niestandardowy dostawca formatu liczbowego jest ignorowany, a NumberFormatInfo obiekt bieżącej kultury jest używany w jego miejscu. W tym przykładzie TelephoneFormatter.GetFormat metoda obsługuje możliwość, że może zostać niewłaściwie przekazana do metody formatowania liczbowego, sprawdzając parametr metody i zwracając null , czy reprezentuje typ inny niż ICustomFormatter.

Jeśli niestandardowy dostawca formatu liczbowego obsługuje zestaw specyfikatorów formatu, upewnij się, że podano domyślne zachowanie, jeśli żaden specyfikator formatu nie jest dostarczany w elemencie formatu używanym w wywołaniu String.Format(IFormatProvider, String, Object[]) metody. W przykładzie "N" jest specyfikatorem formatu domyślnego. Dzięki temu można przekonwertować liczbę na sformatowany numer telefonu, podając specyfikator formatu jawnego. Poniższy przykład ilustruje takie wywołanie metody.

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

Umożliwia również konwersję, jeśli nie ma specyfikatora formatu. Poniższy przykład ilustruje takie wywołanie metody.

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

Jeśli nie zdefiniowano specyfikatora formatu domyślnego ICustomFormatter.Format , implementacja metody powinna zawierać kod, taki jak poniżej, aby platforma .NET mogła zapewnić formatowanie, które kod nie obsługuje.

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

W przypadku tego przykładu metoda, która implementuje ICustomFormatter.Format , ma służyć jako metoda wywołania zwrotnego dla String.Format(IFormatProvider, String, Object[]) metody . W związku z tym sprawdza formatProvider parametr, aby określić, czy zawiera odwołanie do bieżącego TelephoneFormatter obiektu. Można jednak wywołać metodę bezpośrednio z kodu. W takim przypadku można użyć parametru formatProvider , aby podać CultureInfo obiekt lub NumberFormatInfo dostarczający informacje o formatowaniu specyficznym dla kultury.