轉換分類總覽
| 類別 | 方向 | 關鍵字/方法 | 失敗行為 | 效能 |
| 隱含轉換 | 數值擴大 | int → long, float → double | 編譯時保證安全 | 零成本 |
| 參考向上 | Derived → Base, T → Interface | 永不失敗 | 零成本 |
| 顯式轉型 | 數值縮小 | (int)longVal, (byte)intVal | 溢位截斷 / checked 擲出 | 極低 |
| 參考向下 | (Derived)baseRef | InvalidCastException | 極低 |
| 介面轉換 | (IMyInterface)obj | InvalidCastException | 極低 |
| Parse/TryParse | 字串→數值/日期/Enum/Guid | int.Parse, DateTime.TryParse | FormatException / 回傳 false | 中 (解析開銷) |
| 字串→其他 | Enum.TryParse, Guid.TryParse | 回傳 false | 中 |
| ToString/格式化 | 數值/日期/物件→字串 | ToString("F2"), $"{val:N}" | 不失敗 (虛擬方法) | 低~中 |
| Convert 類別 | 任意基礎型別互轉 | Convert.ToInt32, ToDateTime | OverflowException / FormatException | 中 (含 null 檢查) |
| 編碼轉換 | 字串↔位元組陣列 | Encoding.UTF8.GetBytes/GetString | EncoderFallbackException | 中 |
| 集合轉換 | List/Array/IEnumerable 互轉 | .ToList(), .ToArray(), .ToDictionary() | 不失敗 (配置新集合) | O(N) |
數值型別轉換詳解
隱含轉換 (安全、無資料遺失)
// 整數擴大
int i = 42;
long l = i; // 隱含
float f = i; // 隱含 (精度可能遺失,但 C# 允許)
double d = f; // 隱含
// 參考向上
string s = "hello";
object o = s; // 隱含
IEnumerable en = new List(); // 隱含
顯式轉型 (可能遺失資料/擲出例外)
long big = 300;
int small = (int)big; // 300 (正常)
long huge = 3_000_000_000;
int overflow = (int)huge; // -1294967296 (截斷,無例外!)
// 啟用溢位檢查
checked
{
int safe = (int)huge; // ❌ OverflowException
}
// 更安全:Convert.ToInt32 (內含溢位檢查)
int safe2 = Convert.ToInt32(huge); // ❌ OverflowException
浮點數轉整數 (截斷向零)
double d = 3.9;
int trunc = (int)d; // 3 (直接捨棄小數)
int round = (int)Math.Round(d); // 4 (四捨五入)
int floor = (int)Math.Floor(d); // 3
int ceil = (int)Math.Ceiling(d); // 4
字串與數值/日期互轉
Parse / TryParse (標準、高效能)
// 整數
bool ok = int.TryParse("123", out int val); // true, val=123
bool ok2 = int.TryParse("abc", out int val2); // false, val2=0
// 進制指定
int hex = int.Parse("FF", System.Globalization.NumberStyles.HexNumber); // 255
// 浮點數 (文化特性敏感)
double d = double.Parse("3.14", CultureInfo.InvariantCulture); // 強制用 . 做小數點
// 日期時間
DateTime dt = DateTime.Parse("2024-03-15 14:30"); // 依目前文化特性
DateTime dt2 = DateTime.ParseExact("15/03/2024", "dd/MM/yyyy", CultureInfo.InvariantCulture);
// Enum
DayOfWeek dow = Enum.Parse("Monday"); // C# 7.3+ 泛型 Parse
bool ok3 = Enum.TryParse("Friday", out DayOfWeek dow2);
// Guid
Guid g = Guid.Parse("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
Convert 類別 (支援 null、物件輸入)
object[] inputs = { "123", 456L, 3.14, true, null, DateTime.Now };
foreach (var input in inputs)
{
int i = Convert.ToInt32(input); // null → 0, true → 1, DateTime → Exception
// Convert 內部處理 null、IConvertible、IFormattable
}
ToString 格式化 (數值/日期/Enum)
int n = 12345;
n.ToString("N"); // "12,345.00" (千分位)
n.ToString("C"); // "NT$12,345.00" (貨幣)
n.ToString("X"); // "3039" (十六進位大寫)
n.ToString("D8"); // "00012345" (補零)
double d = 0.1234;
d.ToString("P"); // "12.34%" (百分比)
d.ToString("E"); // "1.234000E-001" (科學記號)
DateTime now = DateTime.Now;
now.ToString("yyyy-MM-dd HH:mm:ss"); // "2024-03-15 14:30:05"
now.ToString("o"); // "2024-03-15T14:30:05.1234567+08:00" (ISO 8601)
DayOfWeek dow = DayOfWeek.Monday;
dow.ToString(); // "Monday"
dow.ToString("d"); // "1" (底層數值)
物件型別轉換模式
is / as 模式匹配 (C# 7+)
object obj = "hello";
// 傳統
if (obj is string s)
Console.WriteLine(s.Length);
// C# 7 switch 運算式
string result = obj switch
{
int i => $"Integer: {i}",
string s => $"String: {s.Length} chars",
DateTime dt => dt.ToString("o"),
null => "Null",
_ => "Unknown"
};
// as 操作符 (僅參考型別,失敗回傳 null)
string str = obj as string; // null if not string
使用者定義轉換運算子
struct Celsius
{
public double Degrees { get; }
public Celsius(double d) => Degrees = d;
// 隱式:double → Celsius (安全)
public static implicit operator Celsius(double d) => new Celsius(d);
// 顯式:Celsius → double (可能遺失單位語意)
public static explicit operator double(Celsius c) => c.Degrees;
// 互轉
public static implicit operator Fahrenheit(Celsius c) => new Fahrenheit(c.Degrees * 9/5 + 32);
}
struct Fahrenheit
{
public double Degrees { get; }
public Fahrenheit(double d) => Degrees = d;
public static implicit operator Fahrenheit(double d) => new Fahrenheit(d);
}
var c = new Celsius(25);
Fahrenheit f = c; // 隱式轉換
double d = (double)c; // 顯式轉型
編碼與位元組陣列轉換
string text = "中文 English 😀";
// 字串 → 位元組 (指定編碼)
byte[] utf8 = Encoding.UTF8.GetBytes(text); // 最通用
byte[] utf16 = Encoding.Unicode.GetBytes(text); // UTF-16 LE (Windows 內部)
byte[] ascii = Encoding.ASCII.GetBytes(text); // 非 ASCII 字元變 '?'
// 位元組 → 字串
string back = Encoding.UTF8.GetString(utf8);
// Base64 (二進位轉文字傳輸)
string b64 = Convert.ToBase64String(utf8);
byte[] decoded = Convert.FromBase64String(b64);
// 取得編碼物件
Encoding utf8Enc = Encoding.UTF8;
Encoding gb2312 = Encoding.GetEncoding("gb2312"); // 繁體/簡體中文舊系統
Encoding big5 = Encoding.GetEncoding("big5");
集合與陣列轉換 (LINQ)
int[] array = { 1, 2, 3 };
List list = new List { 4, 5 };
// 陣列 ↔ List
List fromArray = array.ToList();
int[] fromList = list.ToArray();
// IEnumerable 具體化
IEnumerable query = array.Where(x => x > 1);
List materialized = query.ToList(); // 立即執行
// Dictionary
var dict = list.ToDictionary(x => x, x => x * 2); // {1:2, 2:4, 3:6, 4:8, 5:10}
var lookup = list.ToLookup(x => x % 2); // 分組查找
// HashSet (去重)
HashSet unique = list.ToHashSet();
// Stack/Queue
Stack stack = new Stack(list);
Queue queue = new Queue(list);
// DataTable → List (常見 ADO.NET 場景)
List dtos = dataTable.AsEnumerable()
.Select(row => new MyDto { Id = row.Field("Id"), Name = row.Field("Name") })
.ToList();
常見陷阱與最佳實踐
| 陷阱 | 錯誤做法 | 正確做法 |
| 浮點數比較 | if (d == 0.1) | if (Math.Abs(d - 0.1) < 1e-9) |
| 整數溢位靜默 | int x = 2_000_000_000 + 2_000_000_000; | 用 checked 區塊或 long |
| 字串解析例外 | int.Parse(userInput) | int.TryParse(userInput, out _) |
| 日期文化特性 | DateTime.Parse("03/04/2024") (月/日 vs 日/月) | ParseExact(..., "yyyy-MM-dd", InvariantCulture) |
| 編碼預設值 | Encoding.Default (系統相依) | 明確指定 Encoding.UTF8 |
| ToString NullReference | obj.ToString() (obj 可能 null) | obj?.ToString() ?? "" 或 Convert.ToString(obj) |
| as 後未檢查 null | (obj as IDisposable).Dispose() | (obj as IDisposable)?.Dispose() |
效能建議
- 熱路徑避免装箱:
int → object 裝箱配置記憶體,用泛型/介面避免
- 大量字串轉數值:
Span + Utf8Parser (System.Buffers.Text) 比 Parse 快 2-5 倍
- 重複格式化:緩衝
StringBuilder、避免頻繁 ToString 配置
- 編碼重用:
Encoding.UTF8 是單例,勿重複 new UTF8Encoding()
結語
型別轉換是 C# 程式無處不在的基石操作。掌握「隱含 vs 顯式」、「Parse vs TryParse vs Convert」、「編碼明確指定」、「集合具體化時機」、「模式匹配現代語法」,能寫出型別安全、效能優異、錯誤可控的程式碼。記住:編譯器能檢查的靜態轉換優於執行時動態轉換,失敗快速顯性優於靜默錯誤。