在 C# 的型別系統中,is 與 as 是處理多型與型別轉換最核心的兩個運算子。本文將從語法規則、IL 層面、效能考量到實戰模式,全方位剖析兩者的異同與最佳用法。
expression is type
bool:true 表示表達式非 null 且可安全轉換為指定型別;false 表示 null 或轉換會拋例外。| 情況 | 結果 | 說明 |
|---|---|---|
表達式為 null | false | 無物件可驗證,不拋例外 |
| 型別不相容 | false | 如 new object() is string |
| 值型別檢查 | 編譯錯誤 | int i=5; i is decimal → CS0184「運算式永遠是 false」 |
expression as type
null 時回傳 null,永不拋例外。expr is type ? (type)expr : (type)null。object o = 5;
int i = o as int; // 編譯錯誤 CS0039:值型別不可為 null
// 正確寫法
int? i = o as int?; // 可為 null 的值型別
int i = (int)o; // 直接轉型(可能拋 InvalidCastException)
編譯下列程式並觀察 IL:
object o = new Student();
bool b = o is Student; // IL: isinst Student → ldnull → cgt.un
Student s = o as Student; // IL: isinst Student → stloc.1
兩者核心皆呼叫 isinst 指令(測試物件是否為特定類別實例):
is:isinst 結果與 null 比較(cgt.un),產生 bool。as:直接儲存 isinst 結果(可能為 null)。這證明 as 本質上是 is 的語法糖,零額外開銷。
// 傳統寫法
if (obj is Student s)
{
s.Study();
}
// C# 7+ 型別模式(更簡潔,變數作用域限於區塊內)
if (obj is Student student)
{
student.Study();
}
// switch 表達式搭配 (C# 8+)
var msg = obj switch
{
Student s => $"{s.Name} 正在讀書",
Teacher t => $"{t.Name} 正在教學",
_ => "未知角色"
};
| 場景 | 建議 | 理由 |
|---|---|---|
| 僅需檢查型別 | is | 語意清晰,回傳 bool |
| 檢查後立即使用 | is 型別模式 | 單次轉換,變數作用域最小化 |
| 舊版本需檢查後使用 | as + null 檢查 | 避免雙重轉換(is + cast) |
| 高效能熱路徑 | 兩者皆可 | IL 相同,JIT 優化後無差異 |
| 值型別轉換 | 直接轉型或 Nullable | as 不支援非 nullable 值型別 |
NullReferenceException,錯誤位置遠離根因。
if (o is Student) ((Student)o).Study(); 進行兩次型別檢查(雖 JIT 可能優化)。
obj as IInterface 若物件實作介面但非參考轉換(如結構體實作介面會裝箱),行為正確但需理解裝箱成本。
is 是「詢問」,as 是「嘗試」。現代 C# 應優先使用 is 型別模式,兼顧安全、可讀與效能。理解底層 isinst 機制,能在除錯與效能調優時游刃有餘。