Condividi tramite


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

  1. Definire una classe che implementa le interfacce IFormatProvider e ICustomFormatter.

  2. 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:

    1. Determina se l'oggetto Type passato come parametro di metodo rappresenta un'interfaccia ICustomFormatter.

    2. 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.

    3. Se il parametro non rappresenta l'interfaccia ICustomFormatter, GetFormat restituisce null.

  3. 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:

    1. 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.

    2. 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.

    3. Recuperare il valore numerico passato al metodo come parametro arg. Eseguire le eventuali modifiche necessarie per convertirlo nella relativa rappresentazione di stringa.

    4. Restituire la rappresentazione di stringa del parametro arg.

Per utilizzare un oggetto di formattazione numerica personalizzata

  1. Creare una nuova istanza della classe di formattazione personalizzata.

  2. 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.

Vedere anche

Concetti

Procedure relative alla formattazione