C# 的條件運算符 ?:(三元運算符)是表達式級的分支機制,支援短路求值與複雜類型推斷規則。掌握其語意細節,能編寫簡潔且型別安全的程式碼。
結果 = 條件 ? 真分支值 : 假分支值;
執行流程:
條件(必須為 bool 或隱含轉換為 bool)true → 評估 真分支值,結果為其值false → 評估 假分支值,結果為其值關鍵特性:短路求值 — 永遠只評估其中一個分支,另一分支完全不執行。
?: 為右結合:
a ? b : c ? d : e // 等價於 a ? b : (c ? d : e)
建議:巢狀超過兩層時,改用 if-else 或提取方法,提升可讀性。
第二、三運算元類型決定整體表達式類型,規則按優先順序:
| 情況 | 規則 | 結果類型 |
|---|---|---|
| 同類型 | X == Y | X (或 Y) |
| X 隱含轉換 → Y | X → Y 存在,Y → X 不存在 | Y |
| Y 隱含轉換 → X | Y → X 存在,X → Y 不存在 | X |
| 雙向隱含轉換或無轉換 | 其他情況 | 編譯錯誤 |
// int 與 long → long (int 隱含轉換 long)
var result1 = true ? 1 : 2L; // long
// 衍生類別與基底類別 → 基底類別
class Base {} class Derived : Base {}
var result2 = flag ? new Derived() : new Base(); // Base
// null 與參考類型 → 參考類型
string s = cond ? "hello" : null; // string
// int? 與 int → int? (int 隱含轉換 int?)
int? nullable = cond ? 5 : (int?)null; // int?
// int 與 string 無隱含轉換
var bad1 = cond ? 123 : "abc"; // CS0173
// 兩個不相關的介面實作類別
interface IA {} interface IB {}
class A : IA {} class B : IB {}
var bad2 = cond ? new A() : new B(); // CS0173 (需強制轉型)
// 1. 明確轉型 var fixed1 = cond ? (object)123 : (object)"abc"; // object // 2. 統一為共同基底/介面 IA fixed2 = cond ? (IA)new A() : (IA)new B(); // 需 A,B 實作 IA // 3. 使用 Tuple 或自訂類型封裝 var fixed3 = cond ? (Value: 123, Text: "") : (Value: 0, Text: "abc");
// 等價但 ?: 更靈活 var name = user?.Name ?? "Guest"; var name2 = user != null ? user.Name : "Guest";
var classify = (int x) => x > 0 ? "Positive" : x < 0 ? "Negative" : "Zero";
public string DisplayName => _name ?? "Anonymous";
brtrue/brfalse,極高效if-elsecond ? DoA() : DoB() 只呼叫其中一個1 (int) vs 1.0 (double) 導致不匹配x = y > 0 ? 1 : -1 正確,但 x = y > 0 ? 1 : -1 * 2 為 x = y > 0 ? 1 : (-1 * 2)善用 ?: 可減少樣板程式碼,但務必理解其類型推斷規則與短路語意,並在複雜場景選擇更清晰的替代方案。