Vorgehensweise: Definieren und Verwenden von benutzerdefinierten numerischen Formatanbietern
.NET ermöglicht eine umfangreiche Steuerung der Zeichenfolgendarstellung numerischer Werte. Die folgenden Funktionen für die Anpassung des Formats numerischer Werte werden unterstützt:
Standardmäßige Zahlenformatzeichenfolgen, die einen vordefinierten Satz an Formaten für die Konvertierung von Zahlen in ihre Zeichenfolgendarstellung bereitstellen. Sie können diese mit jeder Zahlenformatierungsmethode verwenden, die über einen
format
-Parameter verfügt, z.B. Decimal.ToString(String). Weitere Informationen finden Sie unter Standardmäßige Zahlenformatzeichenfolgen.Benutzerdefinierte Zahlenformatzeichenfolgen, die einen Satz von Symbolen bereitstellen, die kombiniert werden können, um benutzerdefinierte Zahlenformatbezeichner zu definieren. Sie können auch mit jeder Zahlenformatierungsmethode verwendet werden, die über einen
format
-Parameter verfügt, z.B. Decimal.ToString(String). Weitere Informationen finden Sie unter Benutzerdefinierte Zahlenformatzeichenfolgen.Benutzerdefinierte CultureInfo- oder NumberFormatInfo-Objekte, die die beim Anzeigen der Zeichenfolgendarstellungen numerischer Werte verwendeten Symbole und Formatmuster definieren. Sie können diese mit jeder Zahlenformatierungsmethode verwenden, die über einen
provider
-Parameter verfügt, z.B. ToString. Üblicherweise wird derprovider
-Parameter verwendet, um eine kulturspezifische Formatierung anzugeben.
In einigen Fällen (z.B. wenn eine Anwendung eine formatierte Kontonummer, eine ID oder eine Postleitzahl anzeigen muss) sind diese drei Techniken nicht geeignet. .NET ermöglicht Ihnen auch die Definition eines Formatierungsobjekts, bei dem es sich weder um ein CultureInfo-Objekt noch um ein NumberFormatInfo-Objekt handelt, um zu bestimmen, wie ein numerischer Wert formatiert wird. Dieses Thema stellt eine Schrittanleitung für die Implementierung eines solchen Objekts bereit und bietet ein Beispiel, das Telefonnummern formatiert.
Definieren eines benutzerdefinierten Formatanbieters
Definieren Sie eine Klasse, die die IFormatProvider- und ICustomFormatter-Schnittstelle implementiert.
Implementieren Sie die IFormatProvider.GetFormat-Methode. GetFormat ist eine Rückrufmethode, die von der Formatierungsmethode (z.B. der String.Format(IFormatProvider, String, Object[])-Methode) aufgerufen wird, um das Objekt abzurufen, das tatsächlich für die benutzerdefinierte Formatierung zuständig ist. Eine typische Implementierung von GetFormat führt Folgendes aus:
Bestimmt, ob das als Methodenparameter übergebene Type-Objekt eine ICustomFormatter-Schnittstelle darstellt.
Wenn der Parameter die ICustomFormatter-Schnittstelle tatsächlich darstellt, gibt GetFormat ein Objekt zurück, das die für die benutzerdefinierte Formatierung zuständige ICustomFormatter-Schnittstelle implementiert. Üblicherweise gibt das benutzerdefinierte Formatierungsobjekt sich selbst zurück.
Wenn der Parameter die ICustomFormatter-Schnittstelle nicht darstellt, gibt GetFormat
null
zurück.
Implementieren Sie die Format-Methode. Diese Methode wird von der String.Format(IFormatProvider, String, Object[])-Methode aufgerufen und ist für die Rückgabe der Zeichenfolgendarstellung einer Zahl zuständig. Die Implementierung der Methode umfasst üblicherweise Folgendes:
Stellen Sie optional sicher, dass die Methode dazu in der Lage sein soll, Formatierungsdienste bereitzustellen, indem Sie den
provider
-Parameter untersuchen. Bei Formatierungsobjekten, die sowohl IFormatProvider als auch ICustomFormatter implementieren, umfasst dies das Testen desprovider
-Parameters auf Gleichheit mit dem aktuellen Formatierungsobjekt.Bestimmen Sie, ob das Formatierungsobjekt benutzerdefinierte Formatbezeichner unterstützen soll. (Beispielsweise könnte ein Formatbezeichner „N“ angeben, dass eine US-amerikanische Telefonnummer im NANP-Format (Nordamerikanischer Nummerierungsplan) ausgegeben werden soll, und ein Bezeichner „I“ könnte eine Ausgabe im Format der ITU-T-Empfehlung E.123 angeben.) Wenn Formatbezeichner verwendet werden, muss die Methode den angegebenen Formatbezeichner verarbeiten. Der Bezeichner wird im
format
-Parameter der Methode übergeben. Wenn kein Bezeichner vorhanden ist, lautet der Wert desformat
-Parameters String.Empty.Rufen Sie den numerischen Wert ab, der als
arg
-Parameter der Methode übergeben wurde. Führen Sie alle Änderungen durch, die notwendig sind, um den Wert in seine Zeichenfolgendarstellung zu konvertieren.Geben Sie die Zeichenfolgendarstellung des
arg
-Parameters zurück.
Verwenden eines benutzerdefinierten Zahlenformatierungsobjekts
Erstellen Sie eine neue Instanz der benutzerdefinierten Formatierungsklasse.
Rufen Sie die String.Format(IFormatProvider, String, Object[])-Formatierungsmethode auf, und übergeben Sie das benutzerdefinierte Formatierungsobjekt, den Formatierungsbezeichner (oder String.Empty, falls kein Bezeichner verwendet wird) und den numerischen Wert, der formatiert werden soll.
Beispiel
Das folgende Beispiel definiert einen benutzerdefinierten Zahlenformatanbieter namens TelephoneFormatter
, der eine Zahl, die eine US-amerikanische Telefonnummer darstellt, in das entsprechende NANP- oder E.123-Format konvertiert. Die Methode verarbeitet zwei Formatbezeichner: „N“ (zur Ausgabe des NANP-Formats) und „I“ (zur Ausgabe des internationalen E.123-Formats).
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
Der benutzerdefinierte Zahlenformatanbieter kann nur mit der String.Format(IFormatProvider, String, Object[])-Methode verwendet werden. Alle anderen Überladungen der Zahlenformatierungsmethoden (z.B. ToString
), die einen Parameter des Typs IFormatProvider aufweisen, übergeben der IFormatProvider.GetFormat-Implementierung ein Type-Objekt, das den NumberFormatInfo-Typ darstellt. Im Gegenzug erwarten sie, dass die Methode ein NumberFormatInfo-Objekt zurückgibt. Wenn dies nicht der Fall ist, wird der benutzerdefinierte Zahlenformatanbieter ignoriert und stattdessen das NumberFormatInfo-Objekt für die aktuelle Kultur verwendet. Im Beispiel verarbeitet die TelephoneFormatter.GetFormat
-Methode die Möglichkeit, dass sie fälschlicherweise an eine Zahlenformatierungsmethode übergeben wurde, indem sie den Methodenparameter untersucht und null
zurückgibt, wenn dieser einen anderen Typ als ICustomFormatter darstellt.
Wenn ein benutzerdefinierter Zahlenformatanbieter einen Satz von Formatbezeichnern unterstützt, stellen Sie sicher, dass Sie ein Standardverhalten einrichten, falls in dem Formatelement, das im String.Format(IFormatProvider, String, Object[])-Methodenaufruf verwendet wird, kein Formatbezeichner bereitgestellt wird. Im Beispiel ist „N“ der Standardformatbezeichner. Dadurch kann eine Zahl in eine formatierte Telefonnummer konvertiert werden, indem ein expliziter Formatbezeichner bereitgestellt wird. Das folgende Beispiel veranschaulicht einen solchen Methodenaufruf.
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))
Es ermöglicht die Konvertierung aber auch, falls kein Formatbezeichner vorhanden ist. Das folgende Beispiel veranschaulicht einen solchen Methodenaufruf.
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))
Wenn kein Standardformatbezeichner definiert ist, muss Ihre Implementierung der ICustomFormatter.Format-Methode einen Code wie den folgenden beinhalten, damit .NET eine Formatierung bereitstellen kann, die von Ihrem Code nicht unterstützt wird.
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
In diesem Beispiel dient die Methode, die ICustomFormatter.Format implementiert, als eine Rückrufmethode der String.Format(IFormatProvider, String, Object[])-Methode. Daher untersucht diese Methode den formatProvider
-Parameter, um zu ermitteln, ob dieser einen Verweis auf das aktuelle TelephoneFormatter
-Objekt enthält. Die Methode kann jedoch auch direkt aus dem Code aufgerufen werden. In diesem Fall können Sie den formatProvider
-Parameter verwenden, um ein CultureInfo- oder NumberFormatInfo-Objekt bereitzustellen, das kulturspezifische Formatierungsinformationen bereitstellt.