Porady: definiowanie i użycie niestandardowych dostawców formatu liczbowego
Platforma .NET zapewnia obszerną kontrolę nad reprezentacją ciągów 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ągu. 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. Można ich również używać z dowolną metodą formatowania liczbowego, taką jak Decimal.ToString(String), z parametrem
format
. Aby uzyskać szczegółowe informacje, zobacz Niestandardowe ciągi formatu liczbowego.Obiekty niestandardowe CultureInfo lub NumberFormatInfo definiujące 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
.provider
Zazwyczaj parametr służy do określania 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ą niewłaściwe. Platforma .NET umożliwia również zdefiniowanie obiektu formatowania, który nie jest ani obiektem CultureInfo , NumberFormatInfo aby określić sposób formatowania wartości liczbowej. Ten temat zawiera instrukcje krok po kroku dotyczące implementowania takiego obiektu i zawiera przykład formatujący numery telefonów.
Definiowanie niestandardowego dostawcy formatu
Zdefiniuj klasę, która implementuje IFormatProvider interfejsy i ICustomFormatter .
Zaimplementuj metodę IFormatProvider.GetFormat . GetFormat to metoda wywołania zwrotnego, którą metoda formatowania (na String.Format(IFormatProvider, String, Object[]) przykład metoda) wywołuje w celu pobrania obiektu, który jest faktycznie odpowiedzialny za wykonywanie niestandardowego formatowania. Typowa implementacja programu GetFormat obejmuje następujące czynności:
Określa, czy Type obiekt przekazany jako parametr metody reprezentuje ICustomFormatter interfejs.
Jeśli parametr reprezentuje ICustomFormatter interfejs, GetFormat zwraca obiekt, który implementuje ICustomFormatter interfejs, który jest odpowiedzialny za zapewnienie niestandardowego formatowania. Zazwyczaj obiekt formatowania niestandardowego zwraca sam siebie.
Jeśli parametr nie reprezentuje interfejsu ICustomFormatter , GetFormat zwraca wartość
null
.
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:
Opcjonalnie upewnij się, że metoda jest legalnie przeznaczona do świadczenia usług formatowania, sprawdzając
provider
parametr . W przypadku obiektów formatowania, które implementują metody IFormatProvider i ICustomFormatter, obejmuje to przetestowanie parametruprovider
pod kątem równości z bieżącym obiektem formatowania.Ustal, 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 ZALECENIA ITU-T E.123). Jeśli są używane specyfikatory formatu, metoda powinna obsługiwać specyfikator określonego formatu. Jest przekazywany do metody w parametrze
format
. Jeśli nie ma specyfikatora, wartość parametruformat
to String.Empty.Pobierz wartość liczbową przekazaną do metody jako parametr.
arg
Wykonaj wszelkie wymagane manipulacje, aby przekonwertować je na reprezentację ciągu.Zwraca reprezentację ciągu parametru
arg
.
Używanie niestandardowego obiektu formatowania liczbowego
Utwórz nowe wystąpienie niestandardowej klasy formatowania.
Wywołaj metodę String.Format(IFormatProvider, String, Object[]) formatowania, przekazując ją do niestandardowego obiektu formatowania, specyfikator formatowania (lub String.Empty, jeśli nie jest używany), oraz wartość liczbową, która ma być sformatowana.
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 zwraca 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 reprezentującego 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
, jeśli reprezentuje typ inny niż ICustomFormatter.
Jeśli niestandardowy dostawca formatu liczbowego obsługuje zestaw specyfikatorów formatu, upewnij się, że określono domyślne zachowanie, jeśli w elemencie formatu używanym w wywołaniu String.Format(IFormatProvider, String, Object[]) metody nie podano żadnego specyfikatora formatu. W przykładzie "N" jest domyślnym specyfikatorem formatu. Dzięki temu można przekonwertować liczbę na sformatowany numer telefonu, podając jawny specyfikator formatu. 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 domyślnego ICustomFormatter.Format specyfikatora formatu, implementacja metody powinna zawierać kod, taki jak poniższy, aby platforma .NET mogła zapewnić formatowanie, które nie obsługuje kod.
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 parametr, formatProvider
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 , który dostarcza informacje o formatowaniu specyficznym dla kultury.