標準の数値書式の解析精度
.NET で、ToString
および TryFormat
を使用して数値を文字列として書式設定するときに、より高い精度の値がサポートされるようになりました。
注意
.NET 7 で最大有効桁数が再び変更されました。 詳細については、「数値書式指定文字列の最大有効桁数」を参照してください。
変更内容
数値を文字列として書式設定するとき、書式文字列の精度指定子は、結果の文字列の桁数を表します。 書式指定子 (文字列の先頭にある文字) により、精度で合計桁数、有効桁数、または小数点以下の桁数を表すことができます。
以前のバージョンの .NET では、標準の数値書式解析ロジックは 99 以下の有効桁数に制限されています。 数値型によっては、精度はさらに高くなりますが、ToString(string format)
ではそれが正しく展開されません。 たとえば、99 より大きい有効桁数を指定すると (32.ToString("C100")
など)、書式指定文字列は "有効桁数 100 の通貨" ではなく、カスタム数値書式文字列として解釈されます。 カスタム数値書式文字列では、文字は文字リテラルとして解釈されます。 また、無効な書式指定子が含まれる書式文字列は、有効桁数の値によって異なる方法で解釈されます。 H99
では無効な書式指定子を示す FormatException がスローされますが、H100
はカスタム数値書式文字列として解釈されます。
.NET 6 以降では、.NET でサポートされる有効桁数は最大 Int32.MaxValue です。 任意の桁数の書式指定子で構成される書式字列は、有効桁数を持つ標準の数値書式文字列として解釈されます。 次のいずれかまたは両方の条件に対しては、FormatException がスローされます。
- 書式指定子文字は標準書式指定子ではありません。
- 有効桁数が Int32.MaxValue を超えています。
この変更は、すべての数値型に影響を与える解析ロジックで実装されました。
次の表では、さまざまな書式文字列の動作変更を示します。
[書式設定文字列] | 以前の動作 | .NET 6 以降の動作 |
---|---|---|
C2 |
小数点以下 2 桁の通貨を表します | 小数点以下 2 桁の通貨を表します (変更なし) |
C100 |
"C100" を出力するカスタム数値書式文字列を示します。 | 小数点以下 100 桁の通貨を表します |
H99 |
無効な標準書式指定子 "H" のため FormatException がスローされます | 無効な標準書式指定子 "H" のため FormatException がスローされます (変更なし) |
H100 |
カスタム数値書式文字列を表します | 無効な標準書式指定子 "H" のため FormatException がスローされます |
導入されたバージョン
.NET 6
変更理由
この変更により、数値書式解析に対して高い有効桁数を使用したときの予期しない動作が修正されます。
推奨アクション
ほとんどの場合、アクションは必要なく、結果の文字列に正しい有効桁数が表示されます。
ただし、有効桁数が 99 を超える場合に書式指定子がリテラル文字として解釈される以前の動作に戻す場合は、その文字を単一引用符で囲むか、円記号でエスケープします。 たとえば、以前のバージョンの .NET では、42.ToString("G999")
からは G999
が返されます。 その動作を維持するには、書式文字列を "'G'999"
または "\\G999"
に変更します。 これは .NET Framework、.NET Core、.NET 5 以降で機能します。
次の書式文字列は、引き続きカスタム数値書式文字列として解釈されます。
- ASCII アルファベット文字以外の文字 (
$
やè
など) で始まる。 - ASCII アルファベット文字で始まり、その後が ASCII 数字ではない (例:
A$
)。 - ASCII アルファベット文字で始まり、その後に一連の ASCII 数字があり、その後に ASCII 数字文字ではない文字がある (例:
A12A
)。
影響を受ける API
この変更は、すべての数値型に影響を与える解析ロジックで実装されました。
- 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)
関連項目
.NET