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
Definieren Sie eine Klasse, durch die die IFormatProvider-Schnittstelle und die ICustomFormatter-Schnittstelle implementiert wird.
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:
Bestimmt, ob das als Methodenparameter übergebene Type-Objekt eine ICustomFormatter-Schnittstelle darstellt.
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.
Wenn der Parameter keine ICustomFormatter-Schnittstelle darstellt, gibt GetFormat den Wert null zurück.
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:
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.
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.
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.
Lassen Sie die Zeichenfolgendarstellung des arg-Parameters zurückgeben.
So verwenden Sie ein benutzerdefiniertes numerisches Formatierungsobjekt
Erstellen Sie eine neue Instanz der benutzerdefinierten Formatierungsklasse.
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.