核心差異一覽
| 關鍵字 | 轉換類型 | 語法 | 適用場景 |
implicit | 隱式轉換 | Target t = source; | 資訊不遺失、語意自然、無例外風險 |
explicit | 顯式轉換 | Target t = (Target)source; | 可能遺失精度、範圍縮減、語意需強調意圖 |
經典範例:神仙與妖怪互轉
using System;
class Program {
class Immortal {
public string Name;
public Immortal(string name) => Name = name;
// 隱式:神仙 → 妖怪(下凡無風險)
public static implicit operator Monster(Immortal value)
=> new Monster($"{value.Name}:神仙變妖怪?偷偷下凡即可。。。");
}
class Monster {
public string Name;
public Monster(string name) => Name = name;
// 顯式:妖怪 → 神仙(需修煉五百年,強調意圖)
public static explicit operator Immortal(Monster value)
=> new Immortal($"{value.Name}:妖怪想當神仙?再去修煉五百年!");
}
static void Main() {
Immortal immortal = new Immortal("紫霞仙子");
Monster monster1 = immortal; // 隱式轉換
Console.WriteLine(monster1.Name);
Monster monster2 = new Monster("孫悟空");
Immortal immortal2 = (Immortal)monster2; // 顯式轉換
Console.WriteLine(immortal2.Name);
Console.ReadLine();
}
}
輸出結果
紫霞仙子:神仙變妖怪?偷偷下凡即可。。。
孫悟空:妖怪想當神仙?再去修煉五百年!
內建型別對照
| 來源 | 目標 | 轉換 | 關鍵字 |
int | long | 擴大 | implicit |
long | int | 縮減 | explicit |
double | float | 精度遺失 | explicit |
Derived | Base | 向上轉型 | implicit |
Base | Derived | 向下轉型 | explicit |
自訂轉換運算子規則
- 必須是
public static
- 來源或目標型別必須包含運算子定義的類別(雙向至少一方)
- 不能轉換為
object、介面型別、基底類別(已有內建轉換)
implicit 與 explicit 不能針對同一對型別雙向定義(會衝突)
- 轉換運算子不支援多型:
Base b = new Derived(); Target t = (Target)b; 若 Target 只定義 explicit operator Target(Derived) 會編譯錯誤
實務設計指南
- 預設用 implicit:若轉換總是安全、無副作用、語意清晰(如
Wrapper → Value、Dto → Entity 簡單映射)。
- 謹慎用 explicit:可能拋例外、遺失資料、語意上需呼叫端明確確認(如
double → int、string → DateTime 解析)。
- 避免過度使用:隱式轉換鏈(A→B→C)會導致難以追蹤的型別推斷錯誤;複雜映射改用
MapTo() 方法或 AutoMapper。
- 文檔化:XML 註解標註轉換條件、可能例外、資料遺失說明。
進階:使用者定義轉換與多型
class Base { }
class Derived : Base { }
class Target {
public static explicit operator Target(Derived d) => new Target(); // 僅接受 Derived
}
Base b = new Derived();
Target t = (Target)b; // 編譯錯誤:無適用轉換(b 編譯時型別為 Base)
Target t2 = (Target)(Derived)b; // 需雙重轉型
此限制是為了型別安全,避免執行時意外失敗。