Procedura: definire e utilizzare provider di formati numerici personalizzati
Aggiornamento: novembre 2007
.NET Framework offre un ampio controllo sulla rappresentazione di stringa dei valori numerici e supporta le funzionalità seguenti per la personalizzazione del formato dei valori numerici:
Stringhe di formato numerico standard che forniscono un insieme predefinito di formati per la conversione dei numeri nella rispettiva rappresentazione di stringa. È possibile utilizzarle con qualsiasi metodo di formattazione numerica, come Decimal.ToString(String) che include un parametro format. Per informazioni dettagliate, vedere Stringhe di formato numerico standard.
Stringhe di formato numerico personalizzate che forniscono un insieme di simboli che possono essere combinati per definire identificatori di formato numerico personalizzati. È anche possibile utilizzarle con qualsiasi metodo di formattazione numerica, come Decimal.ToString(String) che include un parametro format. Per informazioni dettagliate, vedere Stringhe di formato numerico personalizzato.
Oggetti CultureInfo o NumberFormatInfo personalizzati che definiscono i simboli e i modelli di formato utilizzati per la visualizzazione delle rappresentazioni di stringa di valori numerici. È possibile utilizzarli con qualsiasi metodo di formattazione numerica, come ToString che include un parametro provider. In genere, il parametro provider viene utilizzato per specificare informazioni di formattazione specifiche 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 Framework consente anche di definire un oggetto di formattazione che non è né un oggetto CultureInfo né un oggetto NumberFormatInfo e consente di determinare la modalità di formattazione di un valore numerico. In questo argomento sono contenute istruzioni dettagliate per l'implementazione di tale oggetto ed è inoltre riportato un esempio di formattazione di numeri di telefono.
Per definire un provider di formato personalizzato
Definire una classe che implementa le interfacce IFormatProvider e ICustomFormatter.
Implementare il metodo IFormatProvider.GetFormat, ovvero un metodo di callback richiamato dal metodo di formattazione, ad esempio il metodo String.Format(IFormatProvider, String, array<Object[]), per recuperare l'oggetto responsabile della formattazione personalizzata. Una tipica implementazione di GetFormat effettua le operazioni seguenti:
Determina se l'oggetto Type passato come parametro di metodo rappresenta un'interfaccia ICustomFormatter.
Se il parametro rappresenta l'interfaccia ICustomFormatter, GetFormat restituisce un oggetto che implementa l'interfaccia ICustomFormatter che è 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.
Implementare il metodo Format. Questo metodo viene chiamato dal metodo String.Format(IFormatProvider, String, array<Object[]) ed è responsabile della restituzione della rappresentazione di stringa di un numero. L'implementazione del metodo in genere implica le attività seguenti:
Facoltativamente, assicurarsi che il metodo sia correttamente destinato a fornire servizi di formattazione esaminando il parametro provider. Per la formattazione degli oggetti che implementano entrambi i metodi IFormatProvider e ICustomFormatter, questa operazione richiede il test del parametro provider per verificare l'uguaglianza con l'oggetto di formattazione corrente.
Determinare se l'oggetto di formattazione deve supportare identificatori di formato personalizzati. Un identificatore di formato "N" può, ad esempio, indicare che un numero di telefono americano deve essere restituito in formato NANP mentre un identificatore "I" può indicare un output in formato ITU-T Recommendation E.123. Se si utilizzano 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 parametro format è 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.
Per utilizzare un oggetto di formattazione numerica personalizzata
Creare una nuova istanza della classe di formattazione personalizzata.
Chiamare il metodo di formattazione String.Format(IFormatProvider, String, array<Object[]), passando l'oggetto di formattazione personalizzata, l'identificatore di formattazione (o String.Empty se non viene utilizzato 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 di telefono americano in formato NANP o E.123. Il metodo gestisce due identificatori di formato, "N" (che restituisce il formato NANP) e "I" (che restituisce il formato E.123 internazionale)."
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));
}
}
Il provider di formato numerico personalizzato può essere utilizzato solo con il metodo String.Format(IFormatProvider, String, array<Object[]). Gli altri overload dei metodi di formattazione numerica (ad esempio ToString) che hanno un parametro di tipo IFormatProvider passano all'implementazione IFormatProvider.GetFormat un oggetto Type che rappresenta il tipo NumberFormatInfo. In cambio, prevedono che il metodo restituisca un oggetto NumberFormatInfo. In caso contrario, il provider di formato numerico personalizzato viene ignorato e al suo posto viene utilizzato l'oggetto NumberFormatInfo relativo alle impostazioni cultura correnti. Nell'esempio il metodo TelephoneFormatter.GetFormat gestisce la possibilità che possa 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 formato numerico personalizzato supporta un insieme 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 utilizzato nella chiamata al metodo String.Format(IFormatProvider, String, array<Object[]). Nell'esempio "N" è l'identificatore di formato predefinito. È pertanto possibile convertire un numero in un numero di telefono formattato mediante la specifica di 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. The following example illustrates such a method call.
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 elementi di codice come quelli riportati di seguito in modo da consentire a .NET Framework di fornire la formattazione non supportata dal proprio codice.
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 questo esempio il metodo che implementa ICustomFormatter.Format è destinato a essere utilizzato come metodo di callback per il metodo String.Format(IFormatProvider, String, array<Object[]). Tale metodo esamina dunque 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 utilizzare il parametro formatProvider per specificare un oggetto CultureInfo o NumberFormatInfo che fornisce informazioni di formattazione specifiche delle impostazioni cultura.
Compilazione del codice
Compilare il codice alla riga di comando utilizzando csc.exe o vb.exe. Per compilare il codice in Visual Studio, inserirlo in un modello di progetto di applicazione console.