Procedura: definire e utilizzare provider di formati numerici personalizzati
.NET Framework offre un ampio controllo sulla rappresentazione di stringa dei valori numerici e supporta le funzionalità seguenti per la personalizzazione del formato di tali valori:
Stringhe in formato numerico standard, che forniscono un insieme predefinito di formati per la conversione dei numeri nella rispettiva rappresentazione di stringa. È possibile usarle con qualsiasi metodo di formattazione numerica, ad esempio Decimal.ToString(String), che include un parametro
format
. Per informazioni dettagliate, vedere Stringhe di formato numerico standard.Stringhe in formato numerico personalizzato che forniscono un insieme di simboli che possono essere combinati per definire identificatori di formato numerico personalizzato. È anche possibile usarle con qualsiasi metodo di formattazione numerica, ad esempio Decimal.ToString(String), che include un parametro
format
. Per informazioni dettagliate, vedere Stringhe in formato numerico personalizzato.Oggetti CultureInfo o NumberFormatInfo personalizzati, che definiscono i simboli e i modelli di formato usati per la visualizzazione delle rappresentazioni di stringa di valori numerici. È possibile usarle con qualsiasi metodo di formattazione numerica, ad esempio ToString, che include un parametro
provider
. In genere, il parametroprovider
viene usato per specificare un formato specifico delle impostazioni cultura.
In alcuni casi, ad esempio quando un'applicazione deve visualizzare un numero di account formattato, un numero di identificazione o un codice postale, queste tre tecniche non sono adatte. .NET consente anche di definire un oggetto di formattazione diverso da un oggetto CultureInfo o NumberFormatInfo per determinare come viene formattato un valore numerico. In questo argomento sono contenute istruzioni dettagliate per l'implementazione di tale oggetto ed è anche riportato un esempio di formattazione di numeri di telefono.
Definire un provider di formato personalizzato
Definire una classe che implementa le interfacce IFormatProvider e ICustomFormatter.
Implementa il metodo IFormatProvider.GetFormat. GetFormat è un metodo di callback richiamato dal metodo di formattazione, ad esempio il metodo String.Format(IFormatProvider, String, Object[]), per recuperare l'oggetto effettivamente responsabile della formattazione personalizzata. Una tipica implementazione di GetFormat esegue le operazioni seguenti:
Determina se l'oggetto Type passato come parametro del metodo rappresenta un'interfaccia ICustomFormatter.
Se il parametro non rappresenta l'interfaccia ICustomFormatter, GetFormat restituisce un oggetto che implementa l'interfaccia ICustomFormatter responsabile della formattazione personalizzata. In genere, l'oggetto di formattazione personalizzata restituisce se stesso.
Se il parametro non rappresenta l'interfaccia ICustomFormatter, GetFormat restituisce
null
.
Implementa il metodo Format. Questo metodo viene chiamato dal metodo String.Format(IFormatProvider, String, Object[]) ed è responsabile della restituzione della rappresentazione di stringa di un numero. L'implementazione del metodo in genere implica le attività seguenti:
Facoltativamente, è possibile verificare che il metodo sia legittimamente responsabile di fornire servizi di formattazione esaminando il parametro
provider
. Per la formattazione di oggetti che implementano sia IFormatProvider sia ICustomFormatter, questa operazione comporta l'esecuzione di test sul parametroprovider
per verificarne l'uguaglianza all'oggetto di formattazione corrente.Stabilire se l'oggetto di formattazione deve supportare identificatori di formato personalizzato. Ad esempio, un identificatore di formato "N" potrebbe indicare che un numero di telefono degli Stati Uniti deve essere restituito in formato NANP e un identificatore di formato "I" potrebbe indicare l'output in formato ITU-T Recommendation E.123. Se si usano identificatori di formato, il metodo deve gestire l'identificatore di formato specifico. Quest'ultimo viene passato al metodo nel parametro
format
. Se non è disponibile alcun identificatore, il valore del parametroformat
è String.Empty.Recuperare il valore numerico passato al metodo come parametro
arg
. Eseguire le eventuali modifiche necessarie per convertirlo nella relativa rappresentazione di stringa.Restituire la rappresentazione di stringa del parametro
arg
.
Usare un oggetto di formattazione numerica personalizzato
Creare una nuova istanza della classe di formattazione personalizzata.
Chiamare il metodo di formattazione String.Format(IFormatProvider, String, Object[]), passandovi l'oggetto di formattazione personalizzato, l'identificatore di formattazione (o String.Empty se non è specificato alcun identificatore) e il valore numerico da formattare.
Esempio
Nell'esempio seguente viene definito un provider di formato numerico personalizzato denominato TelephoneFormatter
che converte un numero che rappresenta un numero telefonico degli Stati Uniti nel suo formato NANP oppure E.123. Il metodo gestisce due identificatori di formato, "N" (che restituisce il formato NANP) e "I" (che restituisce il formato E.123 internazionale).
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
Il provider di formati numerici personalizzati può essere usato solo con il metodo String.Format(IFormatProvider, String, Object[]). Gli altri overload di metodi di formattazione numerica, come ToString
, che includono un parametro di tipo IFormatProvider, passano tutti l'implementazione IFormatProvider.GetFormat di un oggetto Type che rappresenta il tipo NumberFormatInfo. In cambio, si aspettano che il metodo restituisca un oggetto NumberFormatInfo. In caso contrario, il provider di formati numerici personalizzati viene ignorato e al suo posto viene usato l'oggetto NumberFormatInfo per le impostazioni cultura correnti. Nell'esempio il metodo TelephoneFormatter.GetFormat
gestisce la possibilità di essere passato erroneamente a un metodo di formattazione numerica esaminando il parametro del metodo e restituendo null
se rappresenta un tipo diverso da ICustomFormatter.
Se un provider di formati numerici personalizzati supporta un set di identificatori di formato, assicurarsi di specificare un comportamento predefinito, nel caso in cui non venga fornito alcun identificatore di formato nell'elemento di formato usato nella chiamata al metodo String.Format(IFormatProvider, String, Object[]). Nell'esempio "N" è l'identificatore di formato predefinito. È pertanto possibile convertire un numero in un numero di telefono formattato specificando un identificatore di formato esplicito. Nell'esempio riportato di seguito viene illustrata questa chiamata al metodo.
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))
L'esecuzione della conversione è possibile anche in assenza di identificatori di formato. Nell'esempio riportato di seguito viene illustrata questa chiamata al metodo.
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));
Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))
Se non è definito alcun identificatore di formato predefinito, l'implementazione del metodo ICustomFormatter.Format deve includere codice come quello riportato di seguito in modo da permettere a .NET di fornire la formattazione non supportata dal codice.
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 questo esempio il metodo che implementa ICustomFormatter.Format ha lo scopo di fungere da metodo di callback per il metodo String.Format(IFormatProvider, String, Object[]). Di conseguenza, il metodo esamina il parametro formatProvider
per determinare se contiene un riferimento all'oggetto TelephoneFormatter
corrente. Il metodo può tuttavia essere chiamato anche direttamente dal codice. In questo caso, è possibile usare il parametro formatProvider
per specificare un oggetto CultureInfo o NumberFormatInfo che fornisce informazioni di formattazione specifiche delle impostazioni cultura.