Precisão da análise de formato numérico padrão
O .NET agora dá suporte a valores de precisão maiores ao formatar números como cadeias de caracteres usando ToString
e TryFormat
.
Observação
A precisão máxima foi alterada novamente no .NET 7. Para obter mais informações, confira Precisão máxima de cadeias de caracteres de formato numérico.
Descrição das alterações
Ao formatar números como cadeias de caracteres, o especificador de precisão na cadeia de caracteres de formato representa o número de dígitos na cadeia de caracteres resultante. Dependendo do especificador de formato, que é o caractere no início da cadeia de caracteres, a precisão pode representar o número total de dígitos, o número de dígitos significativos ou o número de dígitos decimais.
Nas versões anteriores do .NET, a lógica de análise de formato numérico padrão era limitada a uma precisão de até 99. Alguns tipos numéricos têm uma precisão maior, mas ToString(string format)
não os expõem corretamente. Se você especificar uma precisão maior que 99, por exemplo, 32.ToString("C100")
, a cadeia de caracteres de formato será interpretada como uma cadeia de caracteres de formato numérico personalizado e não como "moeda com precisão 100". Em cadeias de caracteres de formato numérico personalizado, os caracteres são interpretados como literais de caracteres. Além disso, uma cadeia de caracteres de formato que contém um especificador de formato inválido é interpretada de modo diferente, dependendo do valor de precisão. H99
gera uma FormatException para o especificador de formato inválido, enquanto H100
é interpretado como uma cadeia de caracteres de formato numérico personalizado.
Do .NET 6, o .NET dá suporte a uma precisão de até Int32.MaxValue. Uma cadeia de caracteres de formato que consiste em um especificador de formato com qualquer número de dígitos é interpretada como uma cadeia de caracteres de formato numérico padrão com precisão. Uma FormatException é gerada para uma das seguintes condições ou para ambas:
- O caractere especificador de formato não é um especificador de formato padrão.
- A precisão é maior que Int32.MaxValue.
Essa alteração foi implementada na lógica de análise que afeta todos os tipos numéricos.
A tabela a seguir mostra as alterações de comportamento em várias cadeias de caracteres de formato.
Cadeia de formato | Comportamento anterior | Comportamento do .NET 6 e posteriores |
---|---|---|
C2 |
Denota a moeda com dois dígitos decimais | Denota a moeda com dois dígitos decimais (nenhuma alteração) |
C100 |
Denota uma cadeia de caracteres de formato numérico personalizado que imprime "C100" | Denota a moeda com 100 dígitos decimais |
H99 |
Gera FormatException devido ao especificador de formato padrão inválido "H" | Gera FormatException devido ao especificador de formato padrão inválido "H" (nenhuma alteração) |
H100 |
Denota uma cadeia de caracteres de formato numérico personalizado | Gera FormatException devido ao especificador de formato padrão inválido "H" |
Versão introduzida
.NET 6
Motivo da alteração
Essa alteração corrige o comportamento inesperado ao usar uma precisão mais alta para análise de formato numérico.
Ação recomendada
Na maioria dos casos, nenhuma ação é necessária e a precisão correta será mostrada nas cadeias de caracteres resultantes.
No entanto, se você quiser voltar ao comportamento anterior, em que o especificador de formato é interpretado como um caractere literal quando a precisão é maior que 99, encapsule esse caractere entre aspas simples ou use uma barra invertida como escape. Por exemplo, nas versões anteriores do .NET, 42.ToString("G999")
retorna G999
. Para manter esse comportamento, altere a cadeia de caracteres de formato para "'G'999"
ou "\\G999"
. Isso funcionará no .NET Framework, no .NET Core e no .NET 5 e posteriores.
As seguintes cadeias de caracteres de formato continuarão a ser interpretadas como cadeias de caracteres de formato numérico personalizado:
- As que começam com qualquer caractere que não seja um caractere alfabético ASCII, por exemplo,
$
ouè
. - As que começam com um caractere alfabético ASCII que não é seguido por um dígito ASCII, por exemplo,
A$
. - As que começam com um caractere alfabético ASCII, seguido por uma sequência de dígitos ASCII e depois qualquer caractere que não seja um caractere de dígito ASCII, por exemplo,
A12A
.
APIs afetadas
Essa alteração foi implementada na lógica de análise que afeta todos os tipos numéricos.
- System.Numerics.BigInteger.ToString(String)
- System.Numerics.BigInteger.ToString(String, IFormatProvider)
- System.Numerics.BigInteger.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Int32.ToString(String)
- System.Int32.ToString(String, IFormatProvider)
- System.Int32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.UInt32.ToString(String)
- System.UInt32.ToString(String, IFormatProvider)
- System.UInt32.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Byte.ToString(String)
- System.Byte.ToString(String, IFormatProvider)
- System.Byte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.SByte.ToString(String)
- System.SByte.ToString(String, IFormatProvider)
- System.SByte.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Int16.ToString(String)
- System.Int16.ToString(String, IFormatProvider)
- System.Int16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.UInt16.ToString(String)
- System.UInt16.ToString(String, IFormatProvider)
- System.UInt16.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Int64.ToString(String)
- System.Int64.ToString(String, IFormatProvider)
- System.Int64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.UInt64.ToString(String)
- System.UInt64.ToString(String, IFormatProvider)
- System.UInt64.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Half.ToString(String)
- System.Half.ToString(String, IFormatProvider)
- System.Half.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Single.ToString(String)
- System.Single.ToString(String, IFormatProvider)
- System.Single.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Double.ToString(String)
- System.Double.ToString(String, IFormatProvider)
- System.Double.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)
- System.Decimal.ToString(String)
- System.Decimal.ToString(String, IFormatProvider)
- System.Decimal.TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)