Postupy: Definování a používání vlastních poskytovatelů číselného formátu

.NET poskytuje rozsáhlou kontrolu nad řetězcovou reprezentací číselných hodnot. Podporuje následující funkce pro přizpůsobení formátu číselných hodnot:

  • Standardní řetězce číselného formátu, které poskytují předdefinovanou sadu formátů pro převod čísel na jejich řetězcové vyjádření. Můžete je použít s libovolnou metodou číselného formátování, například Decimal.ToString(String)s parametrem format . Podrobnosti najdete v tématu Standardní řetězce číselného formátu.

  • Vlastní řetězce číselného formátu, které poskytují sadu symbolů, které lze kombinovat a definovat vlastní specifikátory číselného formátu. Lze je také použít s libovolnou metodou číselného formátování, například Decimal.ToString(String)s parametrem format . Podrobnosti najdete v tématu Vlastní řetězce číselného formátu.

  • Vlastní CultureInfo objekty nebo NumberFormatInfo objekty, které definují symboly a vzory formátu použité při zobrazení řetězcových reprezentací číselných hodnot. Můžete je použít s libovolnou metodou číselného formátování, například ToStrings parametrem provider . provider Parametr se obvykle používá k určení formátování specifického pro jazykovou verzi.

V některých případech (například když musí aplikace zobrazit formátované číslo účtu, identifikační číslo nebo PSČ), jsou tyto tři techniky nevhodné. Rozhraní .NET také umožňuje definovat objekt formátování, který není CultureInfo ani objektem NumberFormatInfo , abyste zjistili, jak je číselná hodnota formátována. Toto téma obsahuje podrobné pokyny k implementaci takového objektu a poskytuje příklad, který formátuje telefonní čísla.

Definování zprostředkovatele vlastního formátu

  1. Definujte třídu, která implementuje rozhraníIFormatProvider.ICustomFormatter

  2. Implementujte metodu IFormatProvider.GetFormat . GetFormat je metoda zpětného volání, kterou metoda formátování (například String.Format(IFormatProvider, String, Object[]) metoda) vyvolá k načtení objektu, který je ve skutečnosti zodpovědný za provádění vlastního formátování. Typická implementace GetFormat provede následující:

    1. Určuje, zda Type objekt předaný jako parametr metody představuje ICustomFormatter rozhraní.

    2. Pokud parametr představuje ICustomFormatter rozhraní, vrátí objekt, GetFormat který implementuje ICustomFormatter rozhraní, které je zodpovědné za poskytování vlastního formátování. Objekt vlastního formátování se obvykle vrací sám sebe.

    3. Pokud parametr nepředstavuje ICustomFormatter rozhraní, GetFormat vrátí .null

  3. Implementujte metodu Format . Tato metoda je volána metodou String.Format(IFormatProvider, String, Object[]) a je zodpovědná za vrácení řetězcové reprezentace čísla. Implementace metody obvykle zahrnuje následující:

    1. Volitelně se ujistěte, že metoda je oprávněně určena k poskytování služeb formátování prozkoumáním parametru provider . Pro formátování objektů, které implementují obě IFormatProvider a ICustomFormatter, to zahrnuje testování provider parametr pro rovnost s aktuálním objektem formátování.

    2. Určete, zda má objekt formátování podporovat specifikátory vlastního formátu. (Například specifikátor formátu "N" může znamenat, že telefonní číslo USA by mělo být výstupem ve formátu NANP a "I" může znamenat výstup ve formátu ITU-T E.123.) Pokud se používají specifikátory formátu, měla by metoda zpracovat specifikátor konkrétního formátu. Předá se metodě v parametru format . Pokud není k dispozici žádný specifikátor, hodnota parametru format je String.Empty.

    3. Načtěte číselnou hodnotu předanou metodě jako arg parametr. Proveďte jakoukoli manipulaci, která je potřeba k převodu na řetězcové vyjádření.

    4. Vrátí řetězcovou reprezentaci parametru arg .

Použití vlastního objektu číselného formátování

  1. Vytvořte novou instanci vlastní třídy formátování.

  2. Zavolejte metodu String.Format(IFormatProvider, String, Object[]) formátování, předejte jí objekt vlastního formátování, specifikátor formátování (nebo String.Empty, pokud se nepoužívá) a číselnou hodnotu, kterou chcete naformátovat.

Příklad

Následující příklad definuje vlastního zprostředkovatele číselného formátu s názvem TelephoneFormatter , který převede číslo, které představuje telefonní číslo USA, na jeho formát NANP nebo E.123. Metoda zpracovává dva specifikátory formátu, "N" (který výstupuje formát NANP) a "I" (který výstupuje mezinárodní formát 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

Vlastního zprostředkovatele číselného formátu lze použít pouze s metodou String.Format(IFormatProvider, String, Object[]) . Ostatní přetížení numeric formátovací metody (například ToString) mají parametr typu IFormatProvider všechny předat IFormatProvider.GetFormat implementaci Type objekt, který představuje NumberFormatInfo typ. Ve návratu očekávají, že metoda vrátí NumberFormatInfo objekt. Pokud tomu tak není, vlastní zprostředkovatel číselného formátu se ignoruje a NumberFormatInfo objekt aktuální jazykové verze se použije na svém místě. V příkladu TelephoneFormatter.GetFormat metoda zpracovává možnost, že může být nevhodně předána metodě číselného formátování prozkoumáním parametru metody a vrácením null , pokud představuje jiný typ než ICustomFormatter.

Pokud vlastní zprostředkovatel číselného formátu podporuje sadu specifikátorů formátu, ujistěte se, že jste zadali výchozí chování, pokud není v položce formátu použité ve String.Format(IFormatProvider, String, Object[]) volání metody zadán žádný specifikátor formátu. V příkladu je specifikátorem výchozího formátu "N". To umožňuje převod čísla na formátované telefonní číslo poskytnutím specifikátoru explicitního formátu. Následující příklad znázorňuje takové volání metody.

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

Ale také umožňuje převod nastat, pokud není k dispozici žádný specifikátor formátu. Následující příklad znázorňuje takové volání metody.

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

Pokud není definován žádný specifikátor výchozího ICustomFormatter.Format formátu, vaše implementace metody by měla obsahovat kód, například následující, aby .NET mohl poskytnout formátování, které váš kód nepodporuje.

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

V případě tohoto příkladu je metoda, která implementuje ICustomFormatter.Format , určena jako metoda zpětného volání metody String.Format(IFormatProvider, String, Object[]) . Proto prozkoumá formatProvider parametr, aby určil, zda obsahuje odkaz na aktuální TelephoneFormatter objekt. Metodu však lze volat také přímo z kódu. V takovém případě můžete pomocí parametru formatProviderCultureInfo poskytnout nebo NumberFormatInfo objekt, který poskytuje informace o formátování specifické pro jazykovou verzi.