Formatação de composição

O recurso de formatação de composição do .NET utiliza uma lista de objetos e uma cadeia de caracteres de formato de composição como entrada. Uma cadeia de caracteres de formato composto consiste em texto fixo combinado com espaços reservados indexados, chamados de itens de formato. Esses itens de formato correspondem aos objetos na lista. A operação de formatação produz uma cadeia de caracteres de resultado que consiste no texto fixo original intercalado com a representação de cadeia de caracteres dos objetos na lista.

Importante

Em vez de usar cadeias de caracteres de formato composto, você pode usar cadeias de caracteres interpoladas se a linguagem e a versão usada dão suporte a elas. Uma cadeia de caracteres interpolada contém expressões interpoladas. Cada expressão interpolada é resolvida com o valor da expressão e incluída na cadeia de caracteres resultante quando a cadeia de caracteres é atribuída. Para saber mais, confira Interpolação de cadeia de caracteres (Referência de C#) ou Cadeias de caracteres interpoladas (Referência do Visual Basic).

Os métodos a seguir dão suporte ao recurso de formatação de composição:

Cadeia de formato composto

Uma cadeia de formato de composição e uma lista de objetos são usadas como argumentos dos métodos que dão suporte ao recurso de formatação de composição. Uma cadeia de formato de composição consiste em zero ou mais sequências de texto fixo intercaladas com um ou mais itens de formato. O texto fixo é qualquer cadeia de caracteres que você escolher e cada item de formato corresponde a um objeto ou a uma estrutura demarcada na lista. A representação de cadeia de caracteres de cada objeto substitui o item de formato correspondente.

Considere o seguinte fragmento de código Format:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

O texto fixo é Name = e , hours = . Os itens de formato são {0}, cujo índice 0 corresponde ao objeto name, e {1:hh}, cujo índice 1 corresponde ao objeto DateTime.Now.

Sintaxe do item de formato

Cada item de formato assume a forma a seguir e consiste nos seguintes componentes:

{index[,alignment][:formatString]}

As chaves correspondentes ({ e }) são necessárias.

Componente de índice

O componente obrigatório index, também chamado de especificador de parâmetro, é um número iniciado por 0 que identifica um item correspondente na lista de objetos. Ou seja, o item de formato cujo especificador de parâmetro é 0 formata o primeiro objeto na lista. O item de formato cujo especificador de parâmetro é 1 formata o segundo objeto na lista e assim por diante. O seguinte exemplo inclui quatro especificadores de parâmetro, numerados de zero a três, para representar números primos inferiores a 10:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Vários itens de formato podem fazer referência ao mesmo elemento na lista de objetos ao especificar o mesmo especificador de parâmetro. Por exemplo, você pode formatar o mesmo valor numérico no formato hexadecimal, científico e numérico especificando uma cadeia de caracteres de formato composto, como "0x{0:X} {0:E} {0:N}", como mostra o seguinte exemplo:

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Cada item de formato pode fazer referência a qualquer objeto na lista. Por exemplo, se houver três objetos, você poderá formatar o segundo, o primeiro e o terceiro objeto especificando uma cadeia de caracteres de formato composto, como {1} {0} {2}. Um objeto que não é referenciado por um item de formato é ignorado. Uma FormatException será gerada em tempo de execução se um especificador de parâmetro designar um item fora dos limites da lista de objetos.

Componente de alinhamento

O componente opcional alignment é um inteiro com sinal que indica a largura preferencial do campo formatado. Se o valor de alignment for menor que o comprimento da cadeia de caracteres formatada, alignment será ignorado e o comprimento da cadeia de caracteres formatada será usado como a largura do campo. Os dados formatados no campo serão alinhados à direita se alignment for positivo e serão alinhados à esquerda se alignment for negativo. Se for necessário preenchimento, espaços em branco serão usados. A vírgula é necessária se alignment for especificado.

O exemplo a seguir define duas matrizes, uma contendo os nomes dos funcionários e a outra contendo as horas em que eles trabalharam ao longo de duas semanas. A cadeia de caracteres de formato composto alinha à esquerda os nomes em um campo de 20 caracteres e alinha à direita as horas em um campo de 5 caracteres. A cadeia de caracteres de formato padrão "N1" formata as horas com um dígito fracionário.

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Componente da cadeia de caracteres de formato

O componente formatString opcional é uma cadeia de caracteres de formato apropriada para o tipo de objeto que está sendo formatado. É possível especificar:

  • Uma cadeia de caracteres de formato numérico padrão ou personalizado se o objeto correspondente for um valor numérico.
  • Uma cadeia de caracteres de formato de data e hora padrão ou personalizado se o objeto correspondente for um objeto DateTime.
  • Uma cadeia de caracteres de formato de enumeração se o objeto correspondente for um valor de enumeração.

Se formatString não for especificado, o especificador de formato geral ("G") de um tipo numérico, de data e hora ou de enumeração será usado. Os dois-pontos são necessários quando formatString é especificado.

A tabela a seguir lista tipos ou categorias de tipos na biblioteca de classes .NET que dão suporte a um conjunto predefinido de cadeias de caracteres de formato e fornece links para os artigos que listam as cadeias de caracteres de formato com suporte. A formatação de cadeia de caracteres é um mecanismo extensível que possibilita definir novas cadeias de caracteres de formato para todos os tipos existentes e definir um conjunto de cadeias de caracteres de formato compatíveis com um tipo definido pelo aplicativo.

Para obter mais informações, confira os artigos de interface IFormattable e ICustomFormatter.

Tipo ou categoria de tipo Consulte
Tipos de data e hora (DateTime, DateTimeOffset) Cadeias de caracteres de formato de data e hora padrão

Cadeias de caracteres de formato de data e hora personalizado
Tipos de enumeração (todos os tipos derivados de System.Enum) Cadeias de Caracteres de Formato de Enumeração
Tipos numéricos (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Cadeias de Caracteres de Formato Numérico Padrão

Cadeias de caracteres de formato numérico personalizado
Guid Guid.ToString(String)
TimeSpan Cadeias de caracteres de formato TimeSpan padrão

Cadeias de caracteres de formato TimeSpan personalizado

Chaves de escape

As chaves de abertura e fechamento são interpretadas como o início e o fim de um item de formato. Para exibir uma chave de abertura literal ou uma chave de fechamento, você precisa usar uma sequência de escape. Especifique duas chaves de abertura ({{) no texto fixo para exibir uma chave de abertura ({) ou duas chaves de fechamento (}}) para exibir uma chave de fechamento (}).

Chaves com escape com um item de formato são analisadas de forma diferente entre o .NET e o .NET Framework.

.NET

Chaves podem ser escapadas em torno de um item de formato. Por exemplo, considere o item de formato {{{0:D}}}, que se destina a exibir uma chave de abertura, um valor numérico formatado como um número decimal e uma chave de fechamento. O item de formato é interpretado da seguinte maneira:

  1. As duas primeiras chaves de abertura ({{) têm escape e produzem uma chave de abertura.
  2. Os próximos três caracteres ({0:) são interpretados como o início de um item de formato.
  3. O próximo caractere (D) é interpretado como o especificador de formato numérico padrão decimal.
  4. A última chave (}) é interpretada como o final do item de formato.
  5. As duas últimas chaves de fechamento são escapadas e produzem uma chave de fechamento.
  6. O resultado final exibido é a cadeia de caracteres literal, {6324}.
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

.NET Framework

As chaves em um item de formato são interpretadas sequencialmente na ordem em que são encontradas. Não há suporte para interpretar chaves aninhadas.

A forma como as chaves de escape são interpretadas pode levar a resultados inesperados. Por exemplo, considere o item de formato {{{0:D}}}, que se destina a exibir uma chave de abertura, um valor numérico formatado como um número decimal e uma chave de fechamento. No entanto, o item de formato é interpretado da seguinte maneira:

  1. As duas primeiras chaves de abertura ({{) têm escape e produzem uma chave de abertura.
  2. Os próximos três caracteres ({0:) são interpretados como o início de um item de formato.
  3. O próximo caractere (D) seria interpretado como o especificador de formato numérico padrão decimal, mas as duas chaves de escape seguintes (}}) produzem uma só chave. Como a cadeia de caracteres resultante (D}) não é um especificador de formato numérico padrão, a cadeia de caracteres resultante é interpretada como uma cadeia de caracteres de formato personalizado que significa exibir a cadeia de caracteres literal D}.
  4. A última chave (}) é interpretada como o final do item de formato.
  5. O resultado final exibido é a cadeia de caracteres literal, {D}. O valor numérico que deveria ser formatado não é exibido.
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

Uma forma de escrever o código para evitar a interpretação incorreta de chaves com escape e formatar itens é formatar as chaves e os itens separadamente. Ou seja, na primeira operação de formato, exiba uma chave de abertura literal. Na próxima operação, exiba o resultado do item de formato e, na operação final, exiba uma chave de fechamento literal. O seguinte exemplo ilustra esta abordagem:

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

Ordem de processamento

Se a chamada para o método de formatação composta incluir um argumento IFormatProvider cujo valor não seja null, o runtime chamará o método IFormatProvider.GetFormat para solicitar uma implementação de ICustomFormatter. Se o método puder retornar uma implementação de ICustomFormatter, ele será armazenado em cache durante a chamada do método de formatação de composição.

Cada valor na lista de parâmetros que corresponde a um item de formato é convertido em uma cadeia de caracteres da seguinte maneira:

  1. Se o valor a ser formatado for null, uma cadeia de caracteres vazia String.Empty será retornada.

  2. Se uma implementação de ICustomFormatter estiver disponível, o runtime chamará seu método Format. O runtime passa o valor de formatString do item de formato (ou null se ele não estiver presente) para o método. O runtime também passa a implementação de IFormatProvider para o método. Se a chamada ao método ICustomFormatter.Format retornar null, a execução prosseguirá para a próxima etapa. Caso contrário, o resultado da chamada ICustomFormatter.Format será retornado.

  3. Se o valor implementa a interface IFormattable, o método ToString(String, IFormatProvider) da interface é chamado. Se algum estiver presente no item de formato, o valor de formatString será passado para o método. Caso contrário, null será passado. O argumento IFormatProvider é determinado da seguinte forma:

  4. O método sem parâmetros ToString do tipo, o qual substitui Object.ToString() ou herda o comportamento da sua classe base, é chamado. Nesse caso, a cadeia de caracteres de formato especificada pelo componente formatString no item de formato, quando presente, é ignorada.

O alinhamento é aplicado após as etapas anteriores terem sido executadas.

Exemplos de código

O exemplo a seguir mostra uma cadeia de caracteres criada usando formatação de composição e outra criada usando o método ToString de um objeto. Os dois tipos de formatação produzem resultados equivalentes.

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

Supondo que o dia atual seja uma quinta-feira de maio, o valor de ambas as cadeias de caracteres no exemplo anterior é Thursday May na cultura do inglês dos EUA.

Console.WriteLine expõe a mesma funcionalidade que String.Format. A única diferença entre os dois métodos é que String.Format retorna o resultado como uma cadeia de caracteres, enquanto que Console.WriteLine grava o resultado no fluxo de saída associado ao objeto Console. O seguinte exemplo usa o método Console.WriteLine para formatar o valor de myNumber para um valor de moeda:

int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

O seguinte exemplo demonstra a formatação de vários objetos, incluindo a formatação de um objeto de duas maneiras diferentes:

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

O exemplo a seguir demonstra o uso de alinhamento na formatação. Os argumentos que são formatados são colocados entre caracteres de barra vertical (|) para realçar o alinhamento resultante.

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

Confira também