傳統 switch/case 語句在 C# 中功能有限,無法直接對複雜物件進行模式匹配 (C# 7.0+ 才引入 pattern matching)。本文介紹一種利用擴展方法構建的流暢式 Switch/Case/Default 鏈式 API,支援值比較、條件判斷、預設分支與中斷控制,提升代碼可讀性。
public static class SwitchCaseExtension
{
// 1. Case 容器
public class SwitchCase<TCase, TOther> where TCase : IEquatable<TCase>
{
public TCase Value { get; private set; }
public Action<TOther> Action { get; private set; }
public bool IsMatched { get; set; }
public SwitchCase(TCase value, Action<TOther> action)
{
Value = value;
Action = action;
IsMatched = false;
}
}
// 2. Switch 起始
public static SwitchCase<TCase, TOther> Switch<TCase, TOther>(
this TCase value, Action<TOther> action) where TCase : IEquatable<TCase>
{
return new SwitchCase<TCase, TOther>(value, action);
}
public static SwitchCase<TCase, TOther> Switch<TInput, TCase, TOther>(
this TInput input, Func<TInput, TCase> selector, Action<TOther> action)
where TCase : IEquatable<TCase>
{
return new SwitchCase<TCase, TOther>(selector(input), action);
}
// 3. Case 分支 (值匹配)
public static SwitchCase<TCase, TOther> Case<TCase, TOther>(
this SwitchCase<TCase, TOther> sc, TCase option, TOther other, bool breakAfter = true)
where TCase : IEquatable<TCase>
{
return Case(sc, c => c.Equals(option), other, breakAfter);
}
// 4. Case 分支 (條件判斷)
public static SwitchCase<TCase, TOther> Case<TCase, TOther>(
this SwitchCase<TCase, TOther> sc, Predicate<TCase> predict, TOther other, bool breakAfter = true)
where TCase : IEquatable<TCase>
{
if (sc == null || sc.IsMatched) return sc;
if (predict(sc.Value))
{
sc.Action(other);
sc.IsMatched = true;
return breakAfter ? null : sc;
}
return sc;
}
// 5. Default 分支
public static void Default<TCase, TOther>(
this SwitchCase<TCase, TOther> sc, TOther other)
where TCase : IEquatable<TCase>
{
if (sc == null || sc.IsMatched) return;
sc.Action(other);
}
}
string typeName = string.Empty;
typeId.Switch(s => typeName = s)
.Case("A", "Type A")
.Case("B", "Type B")
.Case("C", "Type C")
.Default("Unknown");
// 更複雜:條件判斷
int number = 42;
number.Switch(n => Console.WriteLine($"Result: {n}"))
.Case(n => n > 100, "Large")
.Case(n => n > 50, "Medium")
.Case(n => n > 0, "Small")
.Default("Zero or Negative");
| 優點 | 缺點 |
|---|---|
| 鏈式語法流暢,閱讀如自然語言 | 非語言原生,IDE 智能提示不如原生 switch |
| 支援複雜條件判斷 (Predicate) | 效能略低於原生 switch (委託呼叫開銷) |
| 可對任何實作 IEquatable 的類型使用 | 需引入擴展方法命名空間 |
| Default 自動處理未匹配情況 | breakAfter 預設 true 可能不符合貫穿需求 |
C# 7.0+ 內建 Pattern Matching 已大幅增強 switch 表達式:
string result = typeId switch
{
"A" => "Type A",
"B" => "Type B",
"C" => "Type C",
_ => "Unknown"
};
// 更進階
string desc = number switch
{
> 100 => "Large",
> 50 => "Medium",
> 0 => "Small",
_ => "Zero or Negative"
};
新專案建議優先使用原生 pattern matching,僅在舊版 .NET Framework 專案中考慮此擴展方案。