前言
ToString() 配合格式字串是 C# 數值顯示的核心。本文系統整理標準格式、自訂格式、文化特性影響與實務陷阱,附完整範例表格可直接複製使用。
標準數值格式字串
| 格式 | 名稱 | 範例 (12345.6789) | 說明 |
| C / c | 貨幣 | NT$12,345.68 | 依文化特性顯示貨幣符號、千分位、小數位 |
| D / d | 十進位 | 12345 | 僅整數型別,可指定最小位數 (D8 → 00012345) |
| E / e | 科學記號 | 1.234568E+004 | 指數部分大小寫對應格式字母 |
| F / f | 定點 | 12345.68 | 固定小數位,F2 為兩位 |
| G / g | 一般 | 12345.6789 | 預設精度,科學記號與定點自動切換 |
| N / n | 數字 | 12,345.68 | 含千分位分隔符,N2 兩位小數 |
| P / p | 百分比 | 1,234,567.89% | 乘 100 加 % 號,P0 無小數 |
| X / x | 十六進位 | 3039 | 僅整數型別,X 為大寫 A-F |
自訂數值格式字串
| 符號 | 名稱 | 範例 | 結果 |
| 0 | 零佔位 | 123.4.ToString("000.00") | 0123.40 |
| # | 數字佔位 | 123.4.ToString("###.##") | 123.4 |
| . | 小數點 | 123.45.ToString("0.0") | 123.5 |
| , | 千分位/縮放 | 1234567.ToString("#,#") | 1,234,567 |
| % | 百分比 | 0.5.ToString("#%") | 50% |
| ‰ | 千分比 | 0.005.ToString("#‰") | 5‰ |
| E0 | 指數記號 | 12345.ToString("0.00E0") | 1.23E4 |
| \'text\' | 字面文字 | 123.ToString("'Year:' 0000") | Year: 0123 |
| ; | 區隔符 | 正數;負數;零 | 見下方範例 |
實戰範例程式碼
using System;
using System.Globalization;
public class NumberFormatDemo
{
public static void Run()
{
decimal dec = 12345.678m;
int integer = 123456;
double dbl = 1234567890;
Console.WriteLine("=== 標準格式 ===");
Console.WriteLine($"C (貨幣) : {dec.ToString("C")}");
Console.WriteLine($"C (美金) : {dec.ToString("C", new CultureInfo("en-US"))}");
Console.WriteLine($"E (科學) : {dec.ToString("E")}");
Console.WriteLine($"F2 (定點2位) : {dec.ToString("F2")}");
Console.WriteLine($"N2 (千分位) : {dec.ToString("N2")}");
Console.WriteLine($"P0 (百分比) : {dec.ToString("P0")}");
Console.WriteLine($"X (十六進位) : {integer.ToString("X")}");
Console.WriteLine("\n=== 自訂格式 ===");
Console.WriteLine($"四捨五入2位 : {dec.ToString("0.00")}");
Console.WriteLine($"不足補零 : {dec.ToString("000000.00")}");
Console.WriteLine($"千分位+2位 : {dec.ToString("#,##0.00")}");
Console.WriteLine($"電話格式 : {dbl.ToString("(###) ###-####")}");
Console.WriteLine($"條件格式 : {FormatWithSign(123)} | {FormatWithSign(-45)} | {FormatWithSign(0)}");
}
static string FormatWithSign(double value)
{
// 正數;負數;零 三段式
return value.ToString("+#;-#;零");
}
}
輸出結果(zh-TW 文化特性)
=== 標準格式 ===
C (貨幣) : NT$12,345.68
C (美金) : $12,345.68
E (科學) : 1.234568E+004
F2 (定點2位) : 12345.68
N2 (千分位) : 12,345.68
P0 (百分比) : 1,234,568%
X (十六進位) : 1E240
=== 自訂格式 ===
四捨五入2位 : 12345.68
不足補零 : 012345.68
千分位+2位 : 12,345.68
電話格式 : (123) 456-7890
條件格式 : +123 | -45 | 零
文化特性與 IFormatProvider
// 明確指定文化特性,避免伺服器設定影響
var tw = new CultureInfo("zh-TW");
var us = new CultureInfo("en-US");
var invariant = CultureInfo.InvariantCulture; // 固定格式,適合儲存/傳輸
decimal value = 1234.5m;
Console.WriteLine(value.ToString("C", tw)); // NT$1,234.50
Console.WriteLine(value.ToString("C", us)); // $1,234.50
Console.WriteLine(value.ToString("N", invariant)); // 1,234.50 (點號小數、逗號千分位)
// 字串插值也支援格式
Console.WriteLine($"價格: {value:C2}"); // 依 CurrentCulture
Console.WriteLine($"價格(美金): {value.ToString("C2", us)}");
常見陷阱與最佳實踐
| 情境 | 錯誤做法 | 正確做法 |
| 金額計算 | float/double 存儲金額 | decimal 型別,避免二進制浮點誤差 |
| 跨文化顯示 | 依賴伺服器 CurrentCulture | 明確傳遞 CultureInfo 或用 InvariantCulture 儲存 |
| 四捨五入 | ToString("F2") 直接顯示 | 先 Math.Round(value, 2, MidpointRounding.AwayFromZero) 再格式化 |
| 大數值格式化 | double 失去精度 | decimal/long 配合自訂格式 |
| 效能敏感 | 頻繁 ToString 分配字串 | 使用 StringBuilder、Span 格式化 (.NET 6+) |
.NET 6+ 新功能:ISpanFormattable / UTF8 格式化
// 直接格式化到 Span,零字串分配
Span buffer = stackalloc byte[32];
int bytesWritten = value.TryFormat(buffer, out _, "C2", CultureInfo.InvariantCulture);
// buffer[..bytesWritten] 即為 UTF-8 位元組
// 適用於高效能日誌、網路封包序列化
總結
熟練掌握標準與自訂格式字串,配合 CultureInfo 明確控制顯示行為,是專業 C# 開發者的基本功。現代專案對金額務必使用 decimal、指定文化特性、考慮 MidpointRounding,高效能場景可探索 ISpanFormattable 零分配格式化。