Freigeben über


Gewusst wie: Definieren und Verwenden von benutzerdefinierten numerischen Formatanbietern

Aktualisiert: November 2007

.NET Framework bietet umfangreiche Steuerungsmöglichkeiten über die Zeichenfolgendarstellung numerischer Werte. Folgende Features zur Anpassung des Formats numerischer Werte werden unterstützt:

  • Standardmäßige Zahlenformatzeichenfolgen, die einen Satz vordefinierter Formate für die Konvertierung von Zahlen in die entsprechende Zeichenfolgendarstellung bereitstellen. Sie können sie mit einer beliebigen numerischen Formatierungsmethode (z. B. Decimal.ToString(String)) verwenden, die über einen format-Parameter verfügt. Ausführliche Informationen finden Sie unter Standardmäßige Zahlenformatzeichenfolgen.

  • Benutzerdefinierte Zahlenformatzeichenfolgen, die eine Reihe von Symbolen bereitstellen, die zur Festlegung benutzerdefinierter Zahlenformatbezeichner kombiniert werden können. Sie können außerdem mit einer beliebigen numerischen Formatierungsmethode (z. B. Decimal.ToString(String)) verwendet werden, die über einen format-Parameter verfügt. Ausführliche Informationen finden Sie unter Benutzerdefinierte Zahlenformatzeichenfolgen.

  • Benutzerdefiniertes CultureInfo-Objekt oder NumberFormatInfo-Objekt zur Definition der Symbole und Formatierungsmuster, die zur Anzeige der Zeichenfolgendarstellungen numerischer Werte verwendet werden. Sie können sie mit einer beliebigen numerischen Formatierungsmethode (z. B. ToString) verwenden, die über einen provider-Parameter verfügt. Normalerweise wird der provider-Parameter verwendet, um eine kulturabhängige Formatierung anzugeben.

In einigen Fällen (z. B. wenn in einer Anwendung eine formatierte Kontonummer, eine ID oder eine Postleitzahl angezeigt werden soll) sind diese drei Techniken nicht geeignet. Über .NET Framework können Sie auch ein Formatierungsobjekt festlegen, das weder ein CultureInfo-Objekt noch ein NumberFormatInfo-Objekt darstellt. Auf diese Weise wird bestimmt, wie ein numerischer Wert formatiert wird. Dieses Thema enthält schrittweise Anleitungen zur Implementierung eines solchen Objekts und umfasst ein Beispiel zur Formatierung von Telefonnummern.

So definieren Sie einen benutzerdefinierten Formatanbieter

  1. Definieren Sie eine Klasse, durch die die IFormatProvider-Schnittstelle und die ICustomFormatter-Schnittstelle implementiert wird.

  2. Implementieren Sie die IFormatProvider.GetFormat-Methode. GetFormat ist eine Rückrufmethode, die von der Formatierungsmethode (z. B. der String.Format(IFormatProvider, String, array<Object[])-Methode) aufgerufen wird, um das Objekt abzurufen, das tatsächlich für die Ausführung der benutzerdefinierten Formatierung zuständig ist. Eine typische Implementierung von GetFormat übernimmt folgende Aufgaben:

    1. Bestimmt, ob das als Methodenparameter übergebene Type-Objekt eine ICustomFormatter-Schnittstelle darstellt.

    2. Wenn der Parameter die ICustomFormatter-Schnittstelle darstellt, gibt GetFormat ein Objekt zurück, durch das die ICustomFormatter-Schnittstelle implementiert wird, die für die benutzerdefinierte Formatierung zuständig ist. Das benutzerdefinierte Formatierungsobjekt gibt normalerweise sich selbst zurück.

    3. Wenn der Parameter keine ICustomFormatter-Schnittstelle darstellt, gibt GetFormat den Wert null zurück.

  3. Implementieren Sie die Format-Methode. Diese Methode wird von der String.Format(IFormatProvider, String, array<Object[])-Methode aufgerufen und ist für die Rückgabe der Zeichenfolgendarstellung einer Zahl zuständig. Das Implementieren der Methode umfasst normalerweise folgende Schritte:

    1. Indem Sie den provider-Parameter überprüfen, können Sie optional feststellen, ob die Methode zur Bereitstellung von Formatierungsdiensten berechtigt ist. Zur Formatierung von Objekten, die sowohl IFormatProvider als auch ICustomFormatter implementieren, muss auch der provider-Parameter auf Übereinstimmung mit dem aktuellen Formatierungsobjekt getestet werden.

    2. Bestimmen Sie, ob das Formatierungsobjekt benutzerdefinierte Formatbezeichner unterstützen soll. (Ein Formatbezeichner "N" kann beispielsweise angeben, dass eine US-Telefonnummer im NANP-Format ausgegeben wird, und ein Formatbezeichner "I" kann angeben, dass sie im ITU-T Recommendation E.123-Format ausgegeben wird.) Wenn Formatbezeichner verwendet werden, sollte die Methode den spezifischen Formatbezeichner behandeln. Er wird an die Methode im format-Parameter übergeben. Wenn kein Bezeichner vorhanden ist, lautet der Wert des format-Parameters String.Empty.

    3. Rufen Sie den numerischen Wert ab, der als arg-Parameter an die Methode übergeben wurde. Führen Sie alle Bearbeitungsschritte aus, die zur Konvertierung in die entsprechende Zeichenfolgendarstellung erforderlich sind.

    4. Lassen Sie die Zeichenfolgendarstellung des arg-Parameters zurückgeben.

So verwenden Sie ein benutzerdefiniertes numerisches Formatierungsobjekt

  1. Erstellen Sie eine neue Instanz der benutzerdefinierten Formatierungsklasse.

  2. Rufen Sie die String.Format(IFormatProvider, String, array<Object[])-Formatierungsmethode auf, und übergeben Sie das benutzerdefinierte Formatierungsobjekt, den Formatbezeichner (oder String.Empty, falls keiner verwendet wird) und den zu formatierenden numerischen Wert an die Methode.

Beispiel

Im folgenden Beispiel wird ein benutzerdefinierter numerischer Formatanbieter mit dem Namen TelephoneFormatter definiert, durch den eine Zahl zur Darstellung einer US-Telefonnummer in das entsprechende NANP- oder E.123-Format konvertiert wird. Die Methode behandelt zwei Formatbezeichner: "N" (zur Ausgabe des NANP-Formats) und "I" (zur Ausgabe des internationalen E.123-Formats).

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
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));
   }
}

Der benutzerdefinierte numerische Formatanbieter kann nur in Verbindung mit der String.Format(IFormatProvider, String, array<Object[])-Methode verwendet werden. Die übrigen Überladungen numerischer Formatierungsmethoden (z. B. ToString), die über einen Parameter vom Typ IFormatProvider verfügen, übergeben alle die IFormatProvider.GetFormat-Implementierung eines Type-Objekts, das den NumberFormatInfo-Typ darstellt. Im Gegenzug wird erwartet, dass die Methode ein NumberFormatInfo-Objekt zurückgibt. Andernfalls wird der benutzerdefinierte numerische Formatanbieter ignoriert und stattdessen das NumberFormatInfo-Objekt für die aktuelle Kultur verwendet. Im Beispiel wird mithilfe der TelephoneFormatter.GetFormat-Methode überprüft, ob die Methode unzulässigerweise an eine numerische Formatierungsmethode übergeben wurde. Dazu wird der Methodenparameter überprüft und null zurückgegeben, wenn er einen anderen Typ als ICustomFormatter aufweist.

Wenn ein benutzerdefinierter numerischer Formatanbieter eine Reihe von Formatbezeichnern unterstützt, sollten Sie ein Standardverhalten für den Fall vorsehen, dass im Formatelement, das im String.Format(IFormatProvider, String, array<Object[])-Methodenaufruf verwendet wird, kein Formatbezeichner angegeben ist. Im Beispiel entspricht "N" dem Standardformatbezeichner. Dadurch kann eine Zahl in eine formatierte Telefonnummer konvertiert werden, indem ein expliziter Formatbezeichner angegeben wird. Im folgenden Beispiel wird ein solcher Methodenaufruf veranschaulicht.

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

Die Konvertierung kann jedoch auch stattfinden, wenn kein Formatbezeichner vorhanden ist. Im folgenden Beispiel wird ein solcher Methodenaufruf veranschaulicht.

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

Wenn kein Standardformatzeichner festgelegt wurde, sollte die Implementierung der ICustomFormatter.Format-Methode etwa folgenden Code enthalten, damit von .NET Framework eine Formatierung bereitgestellt werden kann, die von Ihrem Code ansonsten nicht unterstützt wird.

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

In diesem Beispiel dient die Methode, durch die ICustomFormatter.Format implementiert wird, als Rückrufmethode für die String.Format(IFormatProvider, String, array<Object[])-Methode. Folglich wird der formatProvider-Parameter daraufhin überprüft, ob er einen Verweis auf das aktuelle TelephoneFormatter-Objekt enthält. Die Methode kann jedoch auch direkt über den Code aufgerufen werden. In diesem Fall können Sie den formatProvider-Parameter verwenden, um ein CultureInfo-Objekt oder ein NumberFormatInfo-Objekt bereitzustellen, das kulturabhängige Formatierungsinformationen liefert.

Kompilieren des Codes

Kompilieren Sie den Code über csc.exe oder vb.exe in der Befehlszeile. Um den Code in Visual Studio zu kompilieren, fügen Sie ihn in eine Projektvorlage für eine Konsolenanwendung ein.

Siehe auch

Konzepte

Gewusst-wie-Themen zur Formatierung