Visão geral: como formatar números, datas, enumerações e outros tipos no .NET

Formatação é o processo de converter uma instância de uma classe ou estrutura, ou um valor de enumeração, em uma representação de cadeia de caracteres. A finalidade é exibir a cadeia de caracteres resultante para os usuários ou desserializá-la posteriormente para restaurar o tipo de dados original. Este artigo apresenta os mecanismos de formatação que o .NET oferece.

Observação

A análise é o inverso da formatação. Uma operação de análise cria uma instância de um tipo de dados com base em na representação de sua cadeia de caracteres. Para obter mais informações, consulte Analisar cadeias de caracteres. Para saber mais sobre serialização e desserialização, confira Serialização no .NET.

O mecanismo básico de formatação é a implementação padrão do método Object.ToString, que é abordado na seção Formatação padrão usando o método ToString, mais adiante neste tópico. No entanto, o .NET oferece várias maneiras de modificar e estender o suporte à formatação padrão. Elas incluem o seguinte:

  • Substituir o método Object.ToString para definir uma representação de cadeia de caracteres personalizada do valor de um objeto. Para obter mais informações, veja a seção Substituir o método ToString mais adiante neste tópico.

  • Definir especificadores de formato que permitem que a representação de cadeia de caracteres do valor de um objeto assuma várias formas. Por exemplo, o especificador de formato "X" na instrução a seguir converte um inteiro na representação de cadeia de caracteres de um valor hexadecimal.

    int integerValue = 60312;
    Console.WriteLine(integerValue.ToString("X"));   // Displays EB98.
    
    Dim integerValue As Integer = 60312
    Console.WriteLine(integerValue.ToString("X"))   ' Displays EB98.
    

    Para obter mais informações sobre especificadores de formato, veja a seção Cadeias de caracteres de formato e método ToString.

  • Usar provedores de formato para implementar as convenções de formatação de uma cultura específica. Por exemplo, a instrução a seguir exibe um valor de moeda usando as convenções de formatação da cultura en-US.

    double cost = 1632.54;
    Console.WriteLine(cost.ToString("C",
                      new System.Globalization.CultureInfo("en-US")));
    // The example displays the following output:
    //       $1,632.54
    
    Dim cost As Double = 1632.54
    Console.WriteLine(cost.ToString("C", New System.Globalization.CultureInfo("en-US")))
    ' The example displays the following output:
    '       $1,632.54
    

    Para obter mais informações sobre a formatação com provedores de formato, confira a seção Provedores de formato.

  • A implementação da interface IFormattable para dar suporte tanto à conversão de cadeia de caracteres com a classe Convert quanto à formatação de composição. Para obter mais informações, consulte a seção Interface IFormattable.

  • O uso da formatação de composição para inserir a representação de cadeia de caracteres de um valor em uma cadeia de caracteres maior. Para obter mais informações, veja a seção Formatação composição.

  • Usar a interpolação de cadeia de caracteres, uma sintaxe mais legível para inserir a representação de cadeia de caracteres de um valor em uma cadeia de caracteres maior. Para saber mais, confira Interpolação de cadeia de caracteres.

  • Implementando ICustomFormatter e IFormatProvider para fornecer uma solução completa de formatação personalizada. Para obter mais informações, veja a seção Formatação personalizada com ICustomFormatter.

As seções a seguir examinam esses métodos para converter um objeto em sua representação de cadeia de caracteres.

Formatação padrão usando o método ToString

Cada tipo é derivado de System.Object herda automaticamente um método ToString sem parâmetros, que retorna o nome do tipo por padrão. O exemplo a seguir ilustra o método ToString padrão. Ele define uma classe chamada Automobile que não tem nenhuma implementação. Quando a classe é instanciada e seu método ToString é chamado, ele exibe seu nome de tipo. Observe que o método ToString não é chamado explicitamente no exemplo. O método Console.WriteLine(Object) chama implicitamente o método ToString do objeto é passado para ele como um argumento.

using System;

public class Automobile
{
   // No implementation. All members are inherited from Object.
}

public class Example9
{
   public static void Main()
   {
      Automobile firstAuto = new Automobile();
      Console.WriteLine(firstAuto);
   }
}
// The example displays the following output:
//       Automobile
Public Class Automobile
    ' No implementation. All members are inherited from Object.
End Class

Module Example9
    Public Sub Main9()
        Dim firstAuto As New Automobile()
        Console.WriteLine(firstAuto)
    End Sub
End Module
' The example displays the following output:
'       Automobile

Aviso

A partir do Windows 8.1, o Windows Runtime inclui uma interface IStringable com um único método, IStringable.ToString, que fornece suporte à formatação padrão. No entanto, recomendamos que tipos gerenciados não implementem a interface IStringable. Para obter mais informações, veja a seção "Windows Runtime e a Interface IStringable" na página de referência Object.ToString.

Já que todos os tipos, com a exceção das interfaces, são derivados de Object, essa funcionalidade é fornecida automaticamente para suas estruturas ou classes personalizadas. No entanto, a funcionalidade oferecida pelo método ToString padrão é limitada: embora ele identifique o tipo, não fornece nenhuma informação sobre uma instância do tipo. Para fornecer uma representação de cadeia de caracteres de um objeto que fornece informações sobre o objeto, você deve substituir o método ToString.

Observação

As estruturas herdam de ValueType, que por sua vez é derivado de Object. Embora ValueType substitua Object.ToString, sua implementação é idêntica.

Substituir o método ToString

A exibição do nome de um tipo é geralmente de uso limitado e não permite que os consumidores dos seus tipos diferenciem uma instância da outra. No entanto, você pode substituir o método ToString para fornecer uma representação mais útil do valor de um objeto. O exemplo a seguir define um objeto Temperature e substitui seu método ToString para exibir a temperatura em graus Celsius.

public class Temperature
{
    private decimal temp;

    public Temperature(decimal temperature)
    {
        this.temp = temperature;
    }

    public override string ToString()
    {
        return this.temp.ToString("N1") + "°C";
    }
}

public class Example12
{
    public static void Main()
    {
        Temperature currentTemperature = new Temperature(23.6m);
        Console.WriteLine($"The current temperature is {currentTemperature}");
    }
}
// The example displays the following output:
//       The current temperature is 23.6°C.
Public Class Temperature
    Private temp As Decimal

    Public Sub New(temperature As Decimal)
        Me.temp = temperature
    End Sub

    Public Overrides Function ToString() As String
        Return Me.temp.ToString("N1") + "°C"
    End Function
End Class

Module Example13
    Public Sub Main13()
        Dim currentTemperature As New Temperature(23.6D)
        Console.WriteLine("The current temperature is " +
                          currentTemperature.ToString())
    End Sub
End Module
' The example displays the following output:
'       The current temperature is 23.6°C.

No .NET, o método ToString de cada tipo de valor primitivo foi substituído para exibir o valor do objeto em vez de seu nome. A tabela a seguir mostra a substituição de cada tipo primitivo. Observe que a maioria dos métodos substituídos chama outra sobrecarga do método ToString e passa-a ao especificador de formato "G", que define o formato geral de seu tipo, além de um objeto IFormatProvider que representa a cultura atual.

Tipo Substituição de ToString
Boolean Retorna Boolean.TrueString ou Boolean.FalseString.
Byte Chama Byte.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Byte para a cultura atual.
Char Retorna o caractere como uma cadeia de caracteres.
DateTime Chama DateTime.ToString("G", DatetimeFormatInfo.CurrentInfo) para formatar o valor de data e hora para a cultura atual.
Decimal Chama Decimal.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Decimal para a cultura atual.
Double Chama Double.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Double para a cultura atual.
Int16 Chama Int16.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Int16 para a cultura atual.
Int32 Chama Int32.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Int32 para a cultura atual.
Int64 Chama Int64.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Int64 para a cultura atual.
SByte Chama SByte.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor SByte para a cultura atual.
Single Chama Single.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor Single para a cultura atual.
UInt16 Chama UInt16.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor UInt16 para a cultura atual.
UInt32 Chama UInt32.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor UInt32 para a cultura atual.
UInt64 Chama UInt64.ToString("G", NumberFormatInfo.CurrentInfo) para formatar o valor UInt64 para a cultura atual.

As cadeias de caractere de formato e do método ToString

Contar com o método padrão ToString ou substituir ToString é apropriado quando um objeto tem uma única representação de cadeia de caracteres. No entanto, o valor de um objeto normalmente tem várias representações. Por exemplo, uma temperatura pode ser expressa em graus Fahrenheit, graus Celsius ou kelvins. De forma similar, o valor de inteiro 10 pode ser representado de várias maneiras, incluindo 10, 10,0, 1.0e01 ou US $10,00.

Para permitir que um único valor tenha várias representações de cadeia de caracteres, o .NET usa cadeias de caracteres de formato. Uma cadeia de caracteres de formato é uma cadeia de caracteres que contém um ou mais especificadores de formato predefinidos, que são caracteres únicos ou grupos de caracteres que definem como o método ToString deve formatar sua saída. A cadeia de caracteres de formato é passada como um parâmetro para o método ToString do objeto e determina como a representação de cadeia de caracteres do valor do objeto deve ser exibida.

Todos os tipos numéricos, de data e hora e tipos de enumeração no .NET dão suporte a um conjunto predefinido de especificadores de formato. Você também pode usar cadeias de caracteres de formato para definir várias representações de cadeia de caracteres de seus tipos de dados definidos pelo aplicativo.

Cadeias de caracteres de formato padrão

Uma cadeia de caracteres de formato padrão contém um único especificador de formato, que é um caractere alfabético que define a representação de cadeia de caracteres do objeto ao qual ela é aplicada, junto com um especificador de precisão opcional que afeta a quantos dígitos serão exibidos na cadeia de caracteres de resultado. Se o especificador de precisão for omitido ou não houver suporte a ele, um especificador de formato padrão será equivalente a uma cadeia de caracteres de formato padrão.

O .NET define um conjunto de especificadores de formato padrão para todos os tipos numéricos, todos os tipos de data e hora e todos os tipos de enumeração. Por exemplo, cada uma dessas categorias dá suporte a um especificador de formato padrão "G", que define uma representação de cadeia de caracteres geral de um valor desse mesmo tipo.

Cadeias de caracteres de formato padrão para tipos de enumeração controlam diretamente a representação de cadeia de caracteres de um valor. As cadeias de caracteres de formato passadas para o método ToString de um valor de enumeração determinam se o valor é exibido usando seu nome de cadeia de caracteres (os especificadores de formato "G" e "F"), seu valor integral subjacente (o especificador de formato "D") ou seu valor hexadecimal (o especificador de formato "X"). O exemplo a seguir ilustra o uso de cadeias de caracteres de formato padrão para formatar um valor de enumeração DayOfWeek.

DayOfWeek thisDay = DayOfWeek.Monday;
string[] formatStrings = {"G", "F", "D", "X"};

foreach (string formatString in formatStrings)
   Console.WriteLine(thisDay.ToString(formatString));
// The example displays the following output:
//       Monday
//       Monday
//       1
//       00000001
Dim thisDay As DayOfWeek = DayOfWeek.Monday
Dim formatStrings() As String = {"G", "F", "D", "X"}

For Each formatString As String In formatStrings
    Console.WriteLine(thisDay.ToString(formatString))
Next
' The example displays the following output:
'       Monday
'       Monday
'       1
'       00000001

Para obter informações sobre cadeias de caracteres de formato de enumeração, veja Cadeias de caracteres de formato de enumeração.

Cadeias de caracteres de formato padrão para tipos numéricos geralmente definem uma cadeia de caracteres de resultado cuja aparência exata é controlada por um ou mais valores de propriedade. Por exemplo, o especificador de formato "C" formata um número como um valor de moeda. Quando você chama o método ToString com o especificador de formato "C" como o único parâmetro, os seguintes valores de propriedade do objeto NumberFormatInfo da cultura atual serão usados para definir a representação de cadeia de caracteres do valor numérico:

  • A propriedade CurrencySymbol, que especifica o símbolo da moeda da cultura atual.

  • A propriedade CurrencyNegativePattern ou CurrencyPositivePattern, que retorna um inteiro que determina o seguinte:

    • O posicionamento do símbolo da moeda.

    • Se valores negativos são indicados por um sinal de negativo à esquerda, um sinal de negativo à direita ou parênteses.

    • Se um espaço é ou não exibido entre o valor numérico e o símbolo da moeda.

  • A propriedade CurrencyDecimalDigits, que define o número de dígitos fracionários na cadeia de caracteres de resultado.

  • O propriedade CurrencyDecimalSeparator, que define o símbolo do separador decimal na cadeia de caracteres de resultado.

  • A propriedade CurrencyGroupSeparator, que define o símbolo de separador de grupo.

  • A propriedade CurrencyGroupSizes, que define o número de dígitos em cada grupo à esquerda da vírgula decimal.

  • A propriedade NegativeSign, que determinará o sinal de negativo usado na cadeia de caracteres de resultado se parênteses não forem usados para indicar valores negativos.

Além disso, cadeias de caracteres de formato numérico podem incluir um especificador de precisão. O significado desse especificador depende da cadeia de caracteres de formato com o qual ele é usado, mas ele normalmente indica o número total de dígitos ou o número de dígitos fracionários que devem aparecer na cadeia de caracteres de resultado. Por exemplo, o exemplo a seguir usa a cadeia de caracteres numérica padrão "X4" e um especificador de precisão para criar um valor de cadeia de caracteres com quatro dígitos hexadecimais.

byte[] byteValues = { 12, 163, 255 };
foreach (byte byteValue in byteValues)
   Console.WriteLine(byteValue.ToString("X4"));
// The example displays the following output:
//       000C
//       00A3
//       00FF
Dim byteValues() As Byte = {12, 163, 255}
For Each byteValue As Byte In byteValues
    Console.WriteLine(byteValue.ToString("X4"))
Next
' The example displays the following output:
'       000C
'       00A3
'       00FF

Para obter mais informações sobre cadeias de caracteres de formatação numérica de padrão, veja Cadeias de caracteres de formato numérico padrão.

Cadeias de caracteres de formato padrão para valores de data e hora são aliases para cadeias de caracteres de formato personalizado armazenadas por uma propriedade DateTimeFormatInfo particular. Por exemplo, chamar o método ToString de um valor de data e hora com o especificador de formato "D" exibe a data e hora usando a cadeia de caracteres de formato personalizado armazenada na propriedade DateTimeFormatInfo.LongDatePattern da cultura atual. (Para obter mais informações sobre cadeias de caracteres de formato personalizado, consulte a próxima seção.) O exemplo a seguir ilustra essa relação.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      DateTime date1 = new DateTime(2009, 6, 30);
      Console.WriteLine("D Format Specifier:     {0:D}", date1);
      string longPattern = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern;
      Console.WriteLine("'{0}' custom format string:     {1}",
                        longPattern, date1.ToString(longPattern));
   }
}
// The example displays the following output when run on a system whose
// current culture is en-US:
//    D Format Specifier:     Tuesday, June 30, 2009
//    'dddd, MMMM dd, yyyy' custom format string:     Tuesday, June 30, 2009
Imports System.Globalization

Module Example
    Public Sub Main0()
        Dim date1 As Date = #6/30/2009#
        Console.WriteLine("D Format Specifier:     {0:D}", date1)
        Dim longPattern As String = CultureInfo.CurrentCulture.DateTimeFormat.LongDatePattern
        Console.WriteLine("'{0}' custom format string:     {1}",
                          longPattern, date1.ToString(longPattern))
    End Sub
End Module
' The example displays the following output when run on a system whose
' current culture is en-US:
'    D Format Specifier:     Tuesday, June 30, 2009
'    'dddd, MMMM dd, yyyy' custom format string:     Tuesday, June 30, 2009

Para obter mais informações sobre o padrão de data e cadeias de caracteres de formato de hora, veja Cadeias de caracteres de formato de data e hora padrão.

Você também pode usar cadeias de caracteres de formato padrão para definir a representação de cadeia de caracteres de um objeto definido pelo aplicativo que é produzido pelo método ToString(String) do objeto. Você pode definir os especificadores de formato padrão específicos que dão suporte a seu objeto e você pode determinar se eles diferenciam ou não maiúsculas de minúsculas. A implementação do ToString(String) método deve dar suporte ao seguinte:

  • Um especificador de formato "G" que representa um formato comum ou habitual do objeto. A sobrecarga sem parâmetros do método ToString de seu objeto deve chamar sua sobrecarga ToString(String) e passar cadeia de caracteres de formato padrão "G".

  • Suporte para um especificador de formato que é igual a uma referência nula (Nothing em Visual Basic). Um especificador de formato igual a uma referência nula deve ser considerado equivalente ao especificador de formato "G".

Por exemplo, um Temperature classe interna pode armazenar a temperatura em graus Celsius e usar especificadores de formato para representar o valor do objeto Temperature em graus Fahrenheit, graus Celsius e kelvins. O exemplo a seguir ilustra esse cenário.

using System;

public class Temperature
{
   private decimal m_Temp;

   public Temperature(decimal temperature)
   {
      this.m_Temp = temperature;
   }

   public decimal Celsius
   {
      get { return this.m_Temp; }
   }

   public decimal Kelvin
   {
      get { return this.m_Temp + 273.15m; }
   }

   public decimal Fahrenheit
   {
      get { return Math.Round(((decimal) (this.m_Temp * 9 / 5 + 32)), 2); }
   }

   public override string ToString()
   {
      return this.ToString("C");
   }

   public string ToString(string format)
   {
      // Handle null or empty string.
      if (String.IsNullOrEmpty(format)) format = "C";
      // Remove spaces and convert to uppercase.
      format = format.Trim().ToUpperInvariant();

      // Convert temperature to Fahrenheit and return string.
      switch (format)
      {
         // Convert temperature to Fahrenheit and return string.
         case "F":
            return this.Fahrenheit.ToString("N2") + " °F";
         // Convert temperature to Kelvin and return string.
         case "K":
            return this.Kelvin.ToString("N2") + " K";
         // return temperature in Celsius.
         case "G":
         case "C":
            return this.Celsius.ToString("N2") + " °C";
         default:
            throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
      }
   }
}

public class Example1
{
   public static void Main()
   {
      Temperature temp1 = new Temperature(0m);
      Console.WriteLine(temp1.ToString());
      Console.WriteLine(temp1.ToString("G"));
      Console.WriteLine(temp1.ToString("C"));
      Console.WriteLine(temp1.ToString("F"));
      Console.WriteLine(temp1.ToString("K"));

      Temperature temp2 = new Temperature(-40m);
      Console.WriteLine(temp2.ToString());
      Console.WriteLine(temp2.ToString("G"));
      Console.WriteLine(temp2.ToString("C"));
      Console.WriteLine(temp2.ToString("F"));
      Console.WriteLine(temp2.ToString("K"));

      Temperature temp3 = new Temperature(16m);
      Console.WriteLine(temp3.ToString());
      Console.WriteLine(temp3.ToString("G"));
      Console.WriteLine(temp3.ToString("C"));
      Console.WriteLine(temp3.ToString("F"));
      Console.WriteLine(temp3.ToString("K"));

      Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3));
   }
}
// The example displays the following output:
//       0.00 °C
//       0.00 °C
//       0.00 °C
//       32.00 °F
//       273.15 K
//       -40.00 °C
//       -40.00 °C
//       -40.00 °C
//       -40.00 °F
//       233.15 K
//       16.00 °C
//       16.00 °C
//       16.00 °C
//       60.80 °F
//       289.15 K
//       The temperature is now 16.00 °C.
Public Class Temperature
    Private m_Temp As Decimal

    Public Sub New(temperature As Decimal)
        Me.m_Temp = temperature
    End Sub

    Public ReadOnly Property Celsius() As Decimal
        Get
            Return Me.m_Temp
        End Get
    End Property

    Public ReadOnly Property Kelvin() As Decimal
        Get
            Return Me.m_Temp + 273.15D
        End Get
    End Property

    Public ReadOnly Property Fahrenheit() As Decimal
        Get
            Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
        End Get
    End Property

    Public Overrides Function ToString() As String
        Return Me.ToString("C")
    End Function

    Public Overloads Function ToString(format As String) As String
        ' Handle null or empty string.
        If String.IsNullOrEmpty(format) Then format = "C"
        ' Remove spaces and convert to uppercase.
        format = format.Trim().ToUpperInvariant()

        Select Case format
            Case "F"
                ' Convert temperature to Fahrenheit and return string.
                Return Me.Fahrenheit.ToString("N2") & " °F"
            Case "K"
                ' Convert temperature to Kelvin and return string.
                Return Me.Kelvin.ToString("N2") & " K"
            Case "C", "G"
                ' Return temperature in Celsius.
                Return Me.Celsius.ToString("N2") & " °C"
            Case Else
                Throw New FormatException(String.Format("The '{0}' format string is not supported.", format))
        End Select
    End Function
End Class

Public Module Example1
    Public Sub Main1()
        Dim temp1 As New Temperature(0D)
        Console.WriteLine(temp1.ToString())
        Console.WriteLine(temp1.ToString("G"))
        Console.WriteLine(temp1.ToString("C"))
        Console.WriteLine(temp1.ToString("F"))
        Console.WriteLine(temp1.ToString("K"))

        Dim temp2 As New Temperature(-40D)
        Console.WriteLine(temp2.ToString())
        Console.WriteLine(temp2.ToString("G"))
        Console.WriteLine(temp2.ToString("C"))
        Console.WriteLine(temp2.ToString("F"))
        Console.WriteLine(temp2.ToString("K"))

        Dim temp3 As New Temperature(16D)
        Console.WriteLine(temp3.ToString())
        Console.WriteLine(temp3.ToString("G"))
        Console.WriteLine(temp3.ToString("C"))
        Console.WriteLine(temp3.ToString("F"))
        Console.WriteLine(temp3.ToString("K"))

        Console.WriteLine(String.Format("The temperature is now {0:F}.", temp3))
    End Sub
End Module
' The example displays the following output:
'       0.00 °C
'       0.00 °C
'       0.00 °C
'       32.00 °F
'       273.15 K
'       -40.00 °C
'       -40.00 °C
'       -40.00 °C
'       -40.00 °F
'       233.15 K
'       16.00 °C
'       16.00 °C
'       16.00 °C
'       60.80 °F
'       289.15 K
'       The temperature is now 16.00 °C.

Cadeias de formato personalizadas

Além de cadeias de caracteres de formato padrão, o .NET define cadeias de caracteres de formato personalizado para valores numéricos e valores de data e hora. Uma cadeia de caracteres de formato personalizado consiste em um ou mais especificadores de formato personalizado que definem a representação de cadeia de caracteres de um valor. Por exemplo, a cadeia de caracteres de formato de data e hora personalizada "aaaa/mm/dd hh:mm:ss.ffff t zzz" converte uma data em sua representação de cadeia de caracteres no formato "2008/11/15 07:45:00.0000 P -08:00" para a cultura en-US. Da mesma forma, a cadeia de caracteres de formato personalizado "0000" converte o valor inteiro 12 em "0012". Para obter uma lista completa de cadeias de caracteres de formato personalizado, veja Cadeias de caracteres de formato de data e hora personalizado e Cadeias de caracteres de formato numérico personalizado.

Se uma cadeia de caracteres de formato consiste em um único especificador de formato personalizado, o especificador de formato deve ser precedido pelo símbolo de porcentagem (%) para evitar confusão com um especificador de formato padrão. O exemplo a seguir usa o especificador de formato personalizado "M" para exibir um número de um ou dois dígitos do mês de uma data específica.

DateTime date1 = new DateTime(2009, 9, 8);
Console.WriteLine(date1.ToString("%M"));       // Displays 9
Dim date1 As Date = #09/08/2009#
Console.WriteLine(date1.ToString("%M"))      ' Displays 9

Muitas cadeias de caracteres de formato padrão para valores de data e hora são aliases para cadeias de caracteres de formato personalizado que são definidas pelas propriedades do objeto DateTimeFormatInfo. Cadeias de caracteres de formato personalizado também oferecem flexibilidade considerável no fornecimento de formação definida pelo aplicativo para valores numéricos ou valores de data e hora. Você pode definir suas próprias cadeias de caracteres de resultado personalizadas para valores numéricos e valores de data e hora combinando vários especificadores de formato personalizado em uma única cadeia de caracteres de formato personalizado. O exemplo a seguir define uma cadeia de caracteres de formato personalizado que exibe o dia da semana entre parênteses após o nome do mês, o dia e o ano.

string customFormat = "MMMM dd, yyyy (dddd)";
DateTime date1 = new DateTime(2009, 8, 28);
Console.WriteLine(date1.ToString(customFormat));
// The example displays the following output if run on a system
// whose language is English:
//       August 28, 2009 (Friday)
Dim customFormat As String = "MMMM dd, yyyy (dddd)"
Dim date1 As Date = #8/28/2009#
Console.WriteLine(date1.ToString(customFormat))
' The example displays the following output if run on a system
' whose language is English:
'       August 28, 2009 (Friday)      

O exemplo a seguir define uma cadeia de caracteres de formato personalizado que exibe um valor Int64 como um número de telefone de sete dígitos padrão dos EUA, junto com seu código de área.

using System;

public class Example17
{
   public static void Main()
   {
      long number = 8009999999;
      string fmt = "000-000-0000";
      Console.WriteLine(number.ToString(fmt));
   }
}
// The example displays the following output:
//        800-999-9999
Module Example18
    Public Sub Main18()
        Dim number As Long = 8009999999
        Dim fmt As String = "000-000-0000"
        Console.WriteLine(number.ToString(fmt))
    End Sub
End Module
' The example displays the following output:

' The example displays the following output:
'       800-999-9999

Embora as cadeias de caracteres de formato padrão geralmente tratem da maioria das necessidades de formatação para os tipos definidos pelo aplicativo, você também pode definir especificadores de formato personalizado para formatar seus tipos.

Cadeias de caracteres de formato e tipos do .NET

Todos os tipos numéricos (ou seja, os tipos Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64 e BigInteger), bem como o DateTime, DateTimeOffset, TimeSpan, Guid, e todos os tipos de enumeração, suportam a formatação com cadeias de caracteres de formato. Para obter informações sobre as cadeias de caracteres de formato específicas às quais cada tipo dá suporte, veja os seguintes tópicos:

Título Definição
Cadeias de Caracteres de Formato Numérico Padrão Descreve cadeias de caracteres de formato padrão que criam representações de cadeia de caracteres de valores numéricos frequentemente usadas.
Cadeias de caracteres de formato numérico personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para valores numéricos.
Cadeias de caracteres de formato de data e hora padrão Descreve cadeias de caracteres de formato padrão que criam representações de cadeia de caracteres de valores DateTime e DateTimeOffset frequentemente usadas.
Cadeias de caracteres de formato de data e hora personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para valores DateTime e DateTimeOffset.
Cadeias de caracteres de formato TimeSpan padrão Descreve cadeias de caracteres de formato padrão que criam representações de intervalos de tempo frequentemente usadas.
Cadeias de caracteres de formato TimeSpan personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para intervalos de tempo.
Cadeias de Caracteres de Formato de Enumeração Descreve cadeias de caracteres de formato padrão que são usadas para criar representações de cadeia de caracteres de valores de enumeração.
Guid.ToString(String) Descreve cadeias de caracteres de formato padrão para valores Guid.

Formatação que faz distinção entre culturas com provedores de formato

Embora os especificadores de formato permitam personalizar a formatação de objetos, a produção de uma representação de cadeia de caracteres de objetos significativa geralmente requer informações de formatação adicionais. Por exemplo, formatar um número como um valor de moeda usando a cadeia de caracteres de formato padrão "C" ou então uma cadeia de caracteres de formato personalizado como "$ #,#.00" requer que, no mínimo, informações sobre o símbolo correto da moeda, o separador de grupo e o separador decimal estejam disponíveis para inclusão na cadeia de caracteres formatada. No .NET, essas informações de formatação adicionais são disponibilizadas por meio da interface IFormatProvider, que é fornecida como um parâmetro para um ou mais sobrecargas do método ToString de tipos numéricos e tipos de data e hora. Implementações IFormatProvider são usadas em .NET para dar suporte à formatação específica à cultura. O exemplo a seguir ilustra como a representação de cadeia de caracteres de um objeto é alterado quando ele é formatado com três objetos IFormatProvider que representam diferentes culturas.

using System;
using System.Globalization;

public class Example18
{
   public static void Main()
   {
      decimal value = 1603.42m;
      Console.WriteLine(value.ToString("C3", new CultureInfo("en-US")));
      Console.WriteLine(value.ToString("C3", new CultureInfo("fr-FR")));
      Console.WriteLine(value.ToString("C3", new CultureInfo("de-DE")));
   }
}
// The example displays the following output:
//       $1,603.420
//       1 603,420 €
//       1.603,420 €
Imports System.Globalization

Public Module Example11
    Public Sub Main11()
        Dim value As Decimal = 1603.42D
        Console.WriteLine(value.ToString("C3", New CultureInfo("en-US")))
        Console.WriteLine(value.ToString("C3", New CultureInfo("fr-FR")))
        Console.WriteLine(value.ToString("C3", New CultureInfo("de-DE")))
    End Sub
End Module
' The example displays the following output:
'       $1,603.420
'       1 603,420 €
'       1.603,420 €

A interface IFormatProvider inclui um método, GetFormat(Type), que tem um único parâmetro que especifica o tipo de objeto que fornece informações de formatação. Se o método puder fornecer um objeto desse tipo, ele retornará esse objeto. Caso contrário, ele retornará uma referência nula (Nothing em Visual Basic).

IFormatProvider.GetFormat é um método de retorno de chamada. Quando você chama uma sobrecarga do método ToString que inclui um parâmetro IFormatProvider, ela chama o método GetFormat daquele objeto IFormatProvider. O método GetFormat é responsável por retornar um objeto que fornece as informações de formatação necessárias, conforme especificadas pelo seu parâmetro formatType para o método ToString.

Um número de métodos de conversão de cadeia de caracteres ou formatação inclui um parâmetro de tipo IFormatProvider, mas em muitos casos o valor do parâmetro é ignorado quando o método é chamado. A tabela a seguir lista alguns dos métodos de formatação que usam o parâmetro e o tipo do objeto Type que passam para o método IFormatProvider.GetFormat.

Método Tipo de parâmetro formatType
ToString método de tipos numéricos System.Globalization.NumberFormatInfo
ToString método de tipos de data e hora System.Globalization.DateTimeFormatInfo
String.Format System.ICustomFormatter
StringBuilder.AppendFormat System.ICustomFormatter

Observação

Os métodos ToString dos tipos numéricos e dos tipos de data e hora estão sobrecarregados, e somente algumas das sobrecargas incluem um parâmetro IFormatProvider. Se um método não tiver um parâmetro do tipo IFormatProvider, o objeto retornado pela propriedade CultureInfo.CurrentCulture será passado. Por exemplo, uma chamada para o método Int32.ToString() padrão acaba resultando em uma chamada de método como esta: Int32.ToString("G", System.Globalization.CultureInfo.CurrentCulture).

O .NET fornece três classes que implementam IFormatProvider:

Você também pode implementar seu próprio provedor de formato para substituir qualquer uma dessas classes. No entanto, o método GetFormat da implementação deve retornar um objeto do tipo listado na tabela anterior se ele precisar fornecer informações para o método ToString.

Formatação de valores numéricos que leva em conta a cultura

Por padrão, a formatação de valores numéricos leva em conta a cultura. Se você não especificar uma cultura quando chamar um método de formatação, as convenções de formatação da cultura atual serão usadas. Isso é ilustrado no exemplo a seguir, que altera a cultura atual quatro vezes e, em seguida, chama o método Decimal.ToString(String). Em cada caso, a cadeia de caracteres de resultado reflete as convenções de formatação da cultura atual. Isso ocorre porque os métodos ToString e ToString(String) encapsulam chamadas para o método ToString(String, IFormatProvider) de cada tipo numérico.

using System.Globalization;

public class Example6
{
   public static void Main()
   {
      string[] cultureNames = { "en-US", "fr-FR", "es-MX", "de-DE" };
      Decimal value = 1043.17m;

      foreach (var cultureName in cultureNames) {
         // Change the current culture.
         CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
         Console.WriteLine($"The current culture is {CultureInfo.CurrentCulture.Name}");
         Console.WriteLine(value.ToString("C2"));
         Console.WriteLine();
      }
   }
}
// The example displays the following output:
//       The current culture is en-US
//       $1,043.17
//
//       The current culture is fr-FR
//       1 043,17 €
//
//       The current culture is es-MX
//       $1,043.17
//
//       The current culture is de-DE
//       1.043,17 €
Imports System.Globalization

Module Example6
    Public Sub Main6()
        Dim cultureNames() As String = {"en-US", "fr-FR", "es-MX", "de-DE"}
        Dim value As Decimal = 1043.17D

        For Each cultureName In cultureNames
            ' Change the current culture.
            CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
            Console.WriteLine($"The current culture is {CultureInfo.CurrentCulture.Name}")
            Console.WriteLine(value.ToString("C2"))
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'       The current culture is en-US
'       $1,043.17
'       
'       The current culture is fr-FR
'       1 043,17 €
'       
'       The current culture is es-MX
'       $1,043.17
'       
'       The current culture is de-DE
'       1.043,17 €

Você também pode formatar um valor numérico para uma cultura específica chamando uma sobrecarga ToString que tenha um parâmetro de provider e passando-o a um dos dois elementos a seguir:

O exemplo a seguir usa objetos NumberFormatInfo que representam as culturas americana (Estados Unidos) e britânica (Reino Unido), além das culturas neutras francesa e russa, para formatar um número de ponto flutuante.

using System.Globalization;

public class Example7
{
    public static void Main()
    {
        double value = 1043.62957;
        string[] cultureNames = { "en-US", "en-GB", "ru", "fr" };

        foreach (string? name in cultureNames)
        {
            NumberFormatInfo nfi = CultureInfo.CreateSpecificCulture(name).NumberFormat;
            Console.WriteLine("{0,-6} {1}", name + ":", value.ToString("N3", nfi));
        }
    }
}
// The example displays the following output:
//       en-US: 1,043.630
//       en-GB: 1,043.630
//       ru:    1 043,630
//       fr:    1 043,630
Imports System.Globalization

Module Example7
    Public Sub Main7()
        Dim value As Double = 1043.62957
        Dim cultureNames() As String = {"en-US", "en-GB", "ru", "fr"}

        For Each name In cultureNames
            Dim nfi As NumberFormatInfo = CultureInfo.CreateSpecificCulture(name).NumberFormat
            Console.WriteLine("{0,-6} {1}", name + ":", value.ToString("N3", nfi))
        Next
    End Sub
End Module
' The example displays the following output:
'       en-US: 1,043.630
'       en-GB: 1,043.630
'       ru:    1 043,630
'       fr:    1 043,630

Formatação de valores de data e hora que leva em conta a cultura

Por padrão, a formatação de valores de data e hora leva em conta a cultura. Se você não especificar uma cultura quando chamar um método de formatação, as convenções de formatação da cultura atual serão usadas. Isso é ilustrado no exemplo a seguir, que altera a cultura atual quatro vezes e, em seguida, chama o método DateTime.ToString(String). Em cada caso, a cadeia de caracteres de resultado reflete as convenções de formatação da cultura atual. Isso ocorre porque os métodos DateTime.ToString(), DateTime.ToString(String), DateTimeOffset.ToString() e DateTimeOffset.ToString(String) encapsulam chamadas para os métodos DateTime.ToString(String, IFormatProvider) e DateTimeOffset.ToString(String, IFormatProvider).

using System.Globalization;

public class Example4
{
   public static void Main()
   {
      string[] cultureNames = { "en-US", "fr-FR", "es-MX", "de-DE" };
      DateTime dateToFormat = new DateTime(2012, 5, 28, 11, 30, 0);

      foreach (var cultureName in cultureNames) {
         // Change the current culture.
         CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
         Console.WriteLine($"The current culture is {CultureInfo.CurrentCulture.Name}");
         Console.WriteLine(dateToFormat.ToString("F"));
         Console.WriteLine();
      }
   }
}
// The example displays the following output:
//       The current culture is en-US
//       Monday, May 28, 2012 11:30:00 AM
//
//       The current culture is fr-FR
//       lundi 28 mai 2012 11:30:00
//
//       The current culture is es-MX
//       lunes, 28 de mayo de 2012 11:30:00 a.m.
//
//       The current culture is de-DE
//       Montag, 28. Mai 2012 11:30:00
Imports System.Globalization
Imports System.Threading

Module Example4
    Public Sub Main4()
        Dim cultureNames() As String = {"en-US", "fr-FR", "es-MX", "de-DE"}
        Dim dateToFormat As Date = #5/28/2012 11:30AM#

        For Each cultureName In cultureNames
            ' Change the current culture.
            CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
            Console.WriteLine($"The current culture is {CultureInfo.CurrentCulture.Name}")
            Console.WriteLine(dateToFormat.ToString("F"))
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'       The current culture is en-US
'       Monday, May 28, 2012 11:30:00 AM
'       
'       The current culture is fr-FR
'       lundi 28 mai 2012 11:30:00
'       
'       The current culture is es-MX
'       lunes, 28 de mayo de 2012 11:30:00 a.m.
'       
'       The current culture is de-DE
'       Montag, 28. Mai 2012 11:30:00 

Você também pode formatar um valor de data e hora para uma cultura específica chamando uma sobrecarga DateTime.ToString ou DateTimeOffset.ToString que tenha um parâmetro provider e passando-o a um dos dois elementos a seguir:

O exemplo a seguir usa objetos DateTimeFormatInfo que representam as culturas americana (Estados Unidos) e britânica (Reino Unido), além das culturas neutras francesa e russa para formatar uma data.

using System.Globalization;

public class Example5
{
   public static void Main()
   {
      DateTime dat1 = new(2012, 5, 28, 11, 30, 0);
      string[] cultureNames = { "en-US", "en-GB", "ru", "fr" };

      foreach (var name in cultureNames) {
         DateTimeFormatInfo dtfi = CultureInfo.CreateSpecificCulture(name).DateTimeFormat;
         Console.WriteLine($"{name}: {dat1.ToString(dtfi)}");
      }
   }
}
// The example displays the following output:
//       en-US: 5/28/2012 11:30:00 AM
//       en-GB: 28/05/2012 11:30:00
//       ru: 28.05.2012 11:30:00
//       fr: 28/05/2012 11:30:00
Imports System.Globalization

Module Example5
    Public Sub Main5()
        Dim dat1 As Date = #5/28/2012 11:30AM#
        Dim cultureNames() As String = {"en-US", "en-GB", "ru", "fr"}

        For Each name In cultureNames
            Dim dtfi As DateTimeFormatInfo = CultureInfo.CreateSpecificCulture(name).DateTimeFormat
            Console.WriteLine($"{name}: {dat1.ToString(dtfi)}")
        Next
    End Sub
End Module
' The example displays the following output:
'       en-US: 5/28/2012 11:30:00 AM
'       en-GB: 28/05/2012 11:30:00
'       ru: 28.05.2012 11:30:00
'       fr: 28/05/2012 11:30:00

A interface IFormattable

Normalmente, os tipos que sobrecarregam o método ToString com uma cadeia de caracteres de formato e um parâmetro IFormatProvider também implementam a interface IFormattable. Essa interface tem um único membro, IFormattable.ToString(String, IFormatProvider), que inclui como parâmetros uma cadeia de caracteres de formato e um provedor de formato.

Implementar a interface IFormattable para a classe definida pelo aplicativo oferece duas vantagens:

O exemplo a seguir define uma classe Temperature que implementa a interface IFormattable. Ela dá suporte aos especificadores de formato "C" ou "G" para exibir a temperatura em graus Celsius, o especificador de formato "F" para exibir a temperatura em Fahrenheit e o especificador de formato "K" para exibir a temperatura em Kelvin.

using System;
using System.Globalization;

namespace HotAndCold
{

    public class Temperature : IFormattable
    {
        private decimal m_Temp;

        public Temperature(decimal temperature)
        {
            this.m_Temp = temperature;
        }

        public decimal Celsius
        {
            get { return this.m_Temp; }
        }

        public decimal Kelvin
        {
            get { return this.m_Temp + 273.15m; }
        }

        public decimal Fahrenheit
        {
            get { return Math.Round((decimal)this.m_Temp * 9 / 5 + 32, 2); }
        }

        public override string ToString()
        {
            return this.ToString("G", null);
        }

        public string ToString(string format)
        {
            return this.ToString(format, null);
        }

        public string ToString(string format, IFormatProvider provider)
        {
            // Handle null or empty arguments.
            if (String.IsNullOrEmpty(format))
                format = "G";
            // Remove any white space and covert to uppercase.
            format = format.Trim().ToUpperInvariant();

            if (provider == null)
                provider = NumberFormatInfo.CurrentInfo;

            switch (format)
            {
                // Convert temperature to Fahrenheit and return string.
                case "F":
                    return this.Fahrenheit.ToString("N2", provider) + "°F";
                // Convert temperature to Kelvin and return string.
                case "K":
                    return this.Kelvin.ToString("N2", provider) + "K";
                // Return temperature in Celsius.
                case "C":
                case "G":
                    return this.Celsius.ToString("N2", provider) + "°C";
                default:
                    throw new FormatException(String.Format("The '{0}' format string is not supported.", format));
            }
        }
    }
Public Class Temperature : Implements IFormattable
    Private m_Temp As Decimal

    Public Sub New(temperature As Decimal)
        Me.m_Temp = temperature
    End Sub

    Public ReadOnly Property Celsius() As Decimal
        Get
            Return Me.m_Temp
        End Get
    End Property

    Public ReadOnly Property Kelvin() As Decimal
        Get
            Return Me.m_Temp + 273.15D
        End Get
    End Property

    Public ReadOnly Property Fahrenheit() As Decimal
        Get
            Return Math.Round(CDec(Me.m_Temp * 9 / 5 + 32), 2)
        End Get
    End Property

    Public Overrides Function ToString() As String
        Return Me.ToString("G", Nothing)
    End Function

    Public Overloads Function ToString(format As String) As String
        Return Me.ToString(format, Nothing)
    End Function

    Public Overloads Function ToString(format As String, provider As IFormatProvider) As String _
       Implements IFormattable.ToString

        ' Handle null or empty arguments.
        If String.IsNullOrEmpty(format) Then format = "G"
        ' Remove any white space and convert to uppercase.
        format = format.Trim().ToUpperInvariant()

        If provider Is Nothing Then provider = NumberFormatInfo.CurrentInfo

        Select Case format
     ' Convert temperature to Fahrenheit and return string.
            Case "F"
                Return Me.Fahrenheit.ToString("N2", provider) & "°F"
     ' Convert temperature to Kelvin and return string.
            Case "K"
                Return Me.Kelvin.ToString("N2", provider) & "K"
     ' Return temperature in Celsius.
            Case "C", "G"
                Return Me.Celsius.ToString("N2", provider) & "°C"
            Case Else
                Throw New FormatException(String.Format($"The '{format}' format string is not supported."))
        End Select
    End Function
End Class

O exemplo a seguir instancia um objeto Temperature. Depois, ele chama o método ToString e usa várias cadeias de caracteres de formato de composição para obter diferentes representações de cadeia de caracteres de um objeto Temperature. Cada uma dessas chamadas de método, por sua vez, chama a implementação IFormattable da classe Temperature.

public class Example11
{
    public static void Main()
    {
        CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
        Temperature temp = new Temperature(22m);
        Console.WriteLine(Convert.ToString(temp, new CultureInfo("ja-JP")));
        Console.WriteLine("Temperature: {0:K}", temp);
        Console.WriteLine("Temperature: {0:F}", temp);
        Console.WriteLine(String.Format(new CultureInfo("fr-FR"), "Temperature: {0:F}", temp));
    }
}
// The example displays the following output:
//       22.00°C
//       Temperature: 295.15K
//       Temperature: 71.60°F
//       Temperature: 71,60°F
Public Module Example12
    Public Sub Main12()
        Dim temp As New Temperature(22D)
        CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US")
        Console.WriteLine(Convert.ToString(temp, New CultureInfo("ja-JP")))
        Console.WriteLine($"Temperature: {temp:K}")
        Console.WriteLine($"Temperature: {temp:F}")
        Console.WriteLine(String.Format(New CultureInfo("fr-FR"), $"Temperature: {temp:F}"))
    End Sub
End Module
' The example displays the following output:
'       22.00°C
'       Temperature: 295.15K
'       Temperature: 71.60°F
'       Temperature: 71,60°F

Formatação de composição

Alguns métodos, tais como String.Format e StringBuilder.AppendFormat, dão suporte à formatação de composição. Uma cadeia de caracteres de formato de composição é um tipo de modelo que retorna uma única cadeia de caracteres que incorpora a representação de cadeia de caracteres de zero, um ou mais objetos. Cada objeto é representado na cadeia de caracteres de formato de composição por um item de formato indexado. O índice do item de formato corresponde à posição do objeto que ele representa na lista de parâmetros do método. Os índices são baseados em zero. Por exemplo, na seguinte chamada para o método String.Format, o primeiro item de formato, {0:D}, é substituído pela representação de cadeia de caracteres de thatDate; o segundo item de formato, {1}, é substituído pela representação de cadeia de caracteres de item1 e, por fim, o terceiro item de formato, {2:C2}, é substituído pela representação de cadeia de caracteres de item1.Value.

result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.",
                       thatDate, item1, item1.Value);
Console.WriteLine(result);
// The example displays output like the following if run on a system
// whose current culture is en-US:
//       On 5/1/2009, the inventory of WidgetA was worth $107.44.
result = String.Format("On {0:d}, the inventory of {1} was worth {2:C2}.",
                       thatDate, item1, item1.Value)
Console.WriteLine(result)
' The example displays output like the following if run on a system
' whose current culture is en-US:
'       On 5/1/2009, the inventory of WidgetA was worth $107.44.

Além de substituir um item de formato pela representação de cadeia de caracteres de seu objeto correspondente, os itens de formato também permitem que você controle o seguinte:

  • O modo específico em que um objeto é representado como uma cadeia de caracteres, se o objeto implementa a interface IFormattable e se dá suporte a cadeias de caracteres de formato. Você pode fazer isso seguindo o índice do item de formato com um : (dois-pontos) seguido por uma cadeia de caracteres de formato válido. O exemplo anterior já fez isso ao formatar um valor de data com a cadeia de caracteres de formato (por exemplo, {0:d}) "d" (padrão de data abreviada) e formatando um valor numérico com a cadeia de caracteres de formato "C2" (por exemplo, {2:C2}) para representar o número como um valor de moeda com dois dígitos decimais fracionários.

  • A largura do campo que contém a representação de cadeia de caracteres do objeto e o alinhamento da representação de cadeia de caracteres nesse campo. Você pode fazer isso seguindo o índice do item de formato com uma , (vírgula) seguida da largura do campo. A cadeia de caracteres será alinhada à direita no campo se a largura do campo for um valor positivo ou à esquerda se esse valor for negativo. O exemplo a seguir alinha os valores de data à esquerda em um campo de 20 caracteres e alinha valores decimais com um dígito fracionário à direita em um campo de 11 caracteres.

    DateTime startDate = new DateTime(2015, 8, 28, 6, 0, 0);
    decimal[] temps = { 73.452m, 68.98m, 72.6m, 69.24563m,
                       74.1m, 72.156m, 72.228m };
    Console.WriteLine("{0,-20} {1,11}\n", "Date", "Temperature");
    for (int ctr = 0; ctr < temps.Length; ctr++)
       Console.WriteLine("{0,-20:g} {1,11:N1}", startDate.AddDays(ctr), temps[ctr]);
    
    // The example displays the following output:
    //       Date                 Temperature
    //
    //       8/28/2015 6:00 AM           73.5
    //       8/29/2015 6:00 AM           69.0
    //       8/30/2015 6:00 AM           72.6
    //       8/31/2015 6:00 AM           69.2
    //       9/1/2015 6:00 AM            74.1
    //       9/2/2015 6:00 AM            72.2
    //       9/3/2015 6:00 AM            72.2
    
    Dim startDate As New Date(2015, 8, 28, 6, 0, 0)
    Dim temps() As Decimal = {73.452, 68.98, 72.6, 69.24563,
                               74.1, 72.156, 72.228}
    Console.WriteLine("{0,-20} {1,11}", "Date", "Temperature")
    Console.WriteLine()
    For ctr As Integer = 0 To temps.Length - 1
        Console.WriteLine("{0,-20:g} {1,11:N1}", startDate.AddDays(ctr), temps(ctr))
    Next
    ' The example displays the following output:
    '       Date                 Temperature
    '
    '       8/28/2015 6:00 AM           73.5
    '       8/29/2015 6:00 AM           69.0
    '       8/30/2015 6:00 AM           72.6
    '       8/31/2015 6:00 AM           69.2
    '       9/1/2015 6:00 AM            74.1
    '       9/2/2015 6:00 AM            72.2
    '       9/3/2015 6:00 AM            72.2
    

    Observe que, se o componente de cadeia de caracteres de alinhamento e o componente de cadeia de caracteres de formato estiverem presentes, o primeiro precederá o último (por exemplo, {0,-20:g}.

Para obter mais informações sobre formatação de composição, veja Formatação de composição.

Formatação personalizada com ICustomFormatter

Dois métodos de formatação de composição String.Format(IFormatProvider, String, Object[]) e StringBuilder.AppendFormat(IFormatProvider, String, Object[]), incluem um parâmetro de provedor de formato que dá suporte à formatação personalizada. Quando um desses métodos de formatação é chamado, ele passa um objeto Type que representa uma interface ICustomFormatter para o método GetFormat do provedor de formato. O método GetFormat, em seguida, será responsável por retornar a implementação ICustomFormatter que oferece formatação personalizada.

A interface ICustomFormatter tem um único método, Format(String, Object, IFormatProvider), que é chamado automaticamente por um método de formatação de composição, uma vez para cada item de formato em uma cadeia de caracteres de formato de composição. O método Format(String, Object, IFormatProvider) tem três parâmetros: uma cadeia de caracteres de formato, que representa o argumento formatString em um item de formato, um objeto a ser formatado e um objeto IFormatProvider que oferece serviços de formatação. Normalmente, a classe que implementa ICustomFormatter também implementa IFormatProvider, portanto este último parâmetro é uma referência para a própria classe de formatação personalizada. O método retorna uma representação de cadeia de caracteres formatada personalizada do objeto a ser formatado. Se o método não for capaz de formatar o objeto, ele deverá retornar uma referência nula (Nothing em Visual Basic).

O exemplo a seguir fornece uma implementação ICustomFormatter chamada ByteByByteFormatter que exibe valores inteiros como uma sequência de valores hexadecimais de dois dígitos seguidos por um espaço.

public class ByteByByteFormatter : 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)
   {
      if (! formatProvider.Equals(this)) return null;

      // Handle only hexadecimal format string.
      if (! format.StartsWith("X")) return null;

      byte[] bytes;
      string output = null;

      // Handle only integral types.
      if (arg is Byte)
         bytes = BitConverter.GetBytes((Byte) arg);
      else if (arg is Int16)
         bytes = BitConverter.GetBytes((Int16) arg);
      else if (arg is Int32)
         bytes = BitConverter.GetBytes((Int32) arg);
      else if (arg is Int64)
         bytes = BitConverter.GetBytes((Int64) arg);
      else if (arg is SByte)
         bytes = BitConverter.GetBytes((SByte) arg);
      else if (arg is UInt16)
         bytes = BitConverter.GetBytes((UInt16) arg);
      else if (arg is UInt32)
         bytes = BitConverter.GetBytes((UInt32) arg);
      else if (arg is UInt64)
         bytes = BitConverter.GetBytes((UInt64) arg);
      else
         return null;

      for (int ctr = bytes.Length - 1; ctr >= 0; ctr--)
         output += String.Format("{0:X2} ", bytes[ctr]);

      return output.Trim();
   }
}
Public Class ByteByByteFormatter : 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

        If Not formatProvider.Equals(Me) Then Return Nothing

        ' Handle only hexadecimal format string.
        If Not fmt.StartsWith("X") Then
            Return Nothing
        End If

        ' Handle only integral types.
        If Not typeof arg Is Byte AndAlso
           Not typeof arg Is Int16 AndAlso
           Not typeof arg Is Int32 AndAlso
           Not typeof arg Is Int64 AndAlso
           Not typeof arg Is SByte AndAlso
           Not typeof arg Is UInt16 AndAlso
           Not typeof arg Is UInt32 AndAlso
           Not typeof arg Is UInt64 Then _
              Return Nothing

        Dim bytes() As Byte = BitConverter.GetBytes(arg)
        Dim output As String = Nothing

        For ctr As Integer = bytes.Length - 1 To 0 Step -1
            output += String.Format("{0:X2} ", bytes(ctr))
        Next

        Return output.Trim()
    End Function
End Class

O exemplo a seguir usa a classe ByteByByteFormatter para formatar valores inteiros. Observe que o método ICustomFormatter.Format é chamado mais de uma vez na segunda chamada de método String.Format(IFormatProvider, String, Object[]) e que o provedor padrão NumberFormatInfo é usado na terceira chamada do método porque o método .O método ByteByByteFormatter.Format não reconhece a cadeia de caracteres de formato "N0" e retorna uma referência nula (Nothing no Visual Basic).

public class Example10
{
   public static void Main()
   {
      long value = 3210662321;
      byte value1 = 214;
      byte value2 = 19;

      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X}", value));
      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})",
                                      value1, value2, value1 & value2));
      Console.WriteLine(String.Format(new ByteByByteFormatter(), "{0,10:N0}", value));
   }
}
// The example displays the following output:
//       00 00 00 00 BF 5E D1 B1
//       00 D6 And 00 13 = 00 12 (018)
//       3,210,662,321
Public Module Example10
    Public Sub Main10()
        Dim value As Long = 3210662321
        Dim value1 As Byte = 214
        Dim value2 As Byte = 19

        Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X}", value)))
        Console.WriteLine((String.Format(New ByteByByteFormatter(), "{0:X} And {1:X} = {2:X} ({2:000})",
                                        value1, value2, value1 And value2)))
        Console.WriteLine(String.Format(New ByteByByteFormatter(), "{0,10:N0}", value))
    End Sub
End Module
' The example displays the following output:
'       00 00 00 00 BF 5E D1 B1
'       00 D6 And 00 13 = 00 12 (018)
'       3,210,662,321

Confira também

Título Definição
Cadeias de Caracteres de Formato Numérico Padrão Descreve cadeias de caracteres de formato padrão que criam representações de cadeia de caracteres de valores numéricos frequentemente usadas.
Cadeias de caracteres de formato numérico personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para valores numéricos.
Cadeias de caracteres de formato de data e hora padrão Descreve cadeias de caracteres de formato padrão que criam representações de cadeia de caracteres de valores DateTime frequentemente usadas.
Cadeias de caracteres de formato de data e hora personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para valores DateTime.
Cadeias de caracteres de formato TimeSpan padrão Descreve cadeias de caracteres de formato padrão que criam representações de intervalos de tempo frequentemente usadas.
Cadeias de caracteres de formato TimeSpan personalizado Descreve cadeias de caracteres de formato personalizado que criam formatos específicos de aplicativo para intervalos de tempo.
Cadeias de Caracteres de Formato de Enumeração Descreve cadeias de caracteres de formato padrão que são usadas para criar representações de cadeia de caracteres de valores de enumeração.
Formatação de composição Descreve como inserir um ou mais valores formatados em uma cadeia de caracteres. A cadeia de caracteres pode posteriormente ser exibida no console ou gravada em um fluxo.
Analisando cadeias de caracteres Descreve como inicializar objetos para os valores descritos pelas representações de cadeia de caracteres desses objetos. A análise é a operação inversa da formatação.

Referência