Partilhar via


Como: Definir e usar provedores de formato numérico personalizado

O .NET Framework lhe dá controle amplo sobre a representação de seqüência de valores numéricos. Ele oferece suporte aos seguintes recursos para personalizar o formato de valores numéricos:

  • Sequências de caracteres de formato numérico padrão, que fornecem um conjunto de formatos predefinidos para conversão de números para suas representações de sequência de caracteres. Você pode usá-las com qualquer método de formatação numérica, como Decimal.ToString(String), que tem um parâmetro format. Para obter detalhes, consulte:Sequências de Caracteres de Formato Numérico Padrão.

  • Sequências de formato numérico personalizado, que fornecem um conjunto de símbolos que podem ser combinadas para definir especificadores de formato numérico personalizado. Você pode usá-las com qualquer método de formatação numérica, como Decimal.ToString(String), que tem um parâmetro format. Para obter detalhes, consulte:Sequências de Caracteres de Formato Numérico Personalizado.

  • Objetos personalizados CultureInfo ou NumberFormatInfo, que definem os símbolos e padrões de formato usados para exibir as representações de sequência de valores numéricos. Você pode usá-las com qualquer método de formatação numérica, como ToString, que tem um parâmetro provider. Normalmente, o parâmetro provider é usado para especificar formatação de cultura específica.

Em alguns casos (como quando um aplicativo deve exibir um número de conta formatado, um número de identificação ou um código postal) essas três técnicas são inadequadas. O .NET Framework também permite que você defina um objeto de formatação que não é nem um objeto CultureInfo nem um objeto NumberFormatInfo para determinar como um valor numérico é formatado. Este tópico fornece as instruções de passo a passo para implementar tal objeto e fornece um exemplo que formata números de telefone.

Para definir um provedor de formato personalizado

  1. Defina uma classe que implementa as interfaces IFormatProvider e ICustomFormatter.

  2. Implemente o método IFormatProvider.GetFormat. GetFormaté um método de retorno de chamada que o método de formatação (como o String.Format(IFormatProvider, String, Object[]) método) chama-se para recuperar o objeto que é realmente responsável por executar a formatação personalizada. Uma implementação típica de GetFormat faz o seguinte:

    1. Determina se o objeto Type passado como parâmetro do método representa uma interface ICustomFormatter.

    2. Se o parâmetro representar a interface ICustomFormatter,GetFormat retorna um objeto que implementa a interface ICustomFormatter que é responsável por fornecer formatação personalizada. Normalmente, o objeto de formatação personalizada retorna ele próprio.

    3. Se o parâmetro não representar a interface ICustomFormatter, GetFormat retorna null.

  3. Implemente o método Format. Esse método é chamado pelo método String.Format(IFormatProvider, String, Object[]) e é responsável por retornar a representação da sequência de caracteres de um número. Implementar o método normalmente envolve o seguinte:

    1. Opcionalmente, certifique-se de que o método é legitimamente destinado a fornecer serviços de formatação examinando o parâmetro provider. Para formatar objetos que implementam ambos o IFormatProvider e o ICustomFormatter, isso envolve testar o parâmetro providerpara igualdade com o atual objeto de formatação.

    2. Determine se o objeto de formatação deve suportar especificadores de formato personalizado. (Por exemplo, "N" especificador de formato pode indicar que dos EUA o número de telefone deve ser a saída no formato NANP e um "I" pode indicar a saída no formato de E.123 de recomendação do ITU-T.) Se os especificadores de formato forem usados, o método deve manipular o especificador de formato específico. Ele é passado para o método no parâmetro format. Se nenhum especificador estiver presente, o valor do parâmetro format é String.Empty.

    3. Recupere o valor passado para o método como o parâmetro numérico arg. Execute todas as manipulações que forem necessárias para convertê-lo a uma representação de sequência de caracteres.

    4. Retorne a representação da sequência de caracteres do parâmetro arg.

Para usar um objeto de formatação numérico personalizado

  1. Criar uma nova instância da classe de formatação personalizada.

  2. Chamar o método de formatação String.Format(IFormatProvider, String, Object[]), passando a ele o objeto de formatação personalizado, o especificador de formatação (ou String.Empty, se não for usado), e o valor numérico a ser formatado.

Exemplo

O exemplo a seguir define um provedor de formato numérico personalizado denominado TelephoneFormatter que converte um número que representa dos EUA número de telefone para o seu formato NANP ou E.123. O método lida com dois especificadores de formato, "N" (que gera o formato NANP) e "I" (que gera o formato internacional E.123).

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));
   }
}

O provedor de formato numérico personalizado pode ser usado somente com o método String.Format(IFormatProvider, String, Object[]). Todas as outras sobrecargas de métodos de formatação numérica (como ToString) que têm um parâmetro do tipo IFormatProvider passam à implmentação de IFormatProvider.GetFormat um objeto Type que representa o tipo NumberFormatInfo. Em retorno, eles esperam que o método para retorne um objeto NumberFormatInfo. Se não retornar, o provedor de formato numérico personalizado será ignorado e o objeto NumberFormatInfo para a cultura atual é usado em seu lugar. No exemplo, o método TelephoneFormatter.GetFormat trata a possibilidade de que ele pode ser inadequadamente passado para um método de formatação numérica, examinando o parâmetro do método e retornando null se ele representa um tipo diferente de ICustomFormatter.

Se um provedor de formato numérico personalizado oferece suporte a um conjunto de especificadores de formato, certifique-se de que você forneça um comportamento padrão se nenhum especificador de formato é fornecido no item de formato usado na chamada do método String.Format(IFormatProvider, String, Object[]). No exemplo, "N" é o especificador de formato padrão. Isso permite que um número seja convertido em um número de telefone formatado, fornecendo um especificador de formato explícito. O exemplo a seguir ilustra essa chamada de método.

Console.WriteLine(String.Format(New TelephoneFormatter, "{0:N}", 4257884748))
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0:N}", 4257884748));

Mas ele também permite que a conversão ocorra se nenhum especificador de formato estiver presente. O exemplo a seguir ilustra essa chamada de método.

Console.WriteLine(String.Format(New TelephoneFormatter, "{0}", 4257884748))
Console.WriteLine(String.Format(new TelephoneFormatter(), "{0}", 4257884748));

Se nenhum especificador de formato padrão for definido, sua implementação do método ICustomFormatter.Format deve incluir código como o seguinte para que o .NET Framework possa fornecer a formatação que seu código não suporta.

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();

No caso deste exemplo, o método que implementa ICustomFormatter.Format se destina a servir como um método callback para o método String.Format(IFormatProvider, String, Object[]). Portanto, ele examina o parâmetro formatProvider para determinar se ele contém uma referência ao objeto TelephoneFormatter atual. No entanto, o método também pode ser chamado diretamente a partir do código. Nesse caso, você pode usar o parâmetro formatProvider para fornecer um objeto CultureInfo ou NumberFormatInfo que forneça informações de formatação de cultura específica.

Compilando o código

Compile o código na linha de comando usando o CSC ou vb.exe. Para compilar o código em Visual Studio, colocá-lo no modelo de projeto do console um aplicativo.

Consulte também

Conceitos

Executar operações de formatação