ScottGu 早期示範的 In 擴展方法雖展示擴展語法,但實用性有限。本文逐步改良:params 簡化呼叫 → 泛型約束保證型別安全,打造生產級 In 擴展。
// ScottGu 原版
public static bool In(this object o, IEnumerable c)
{
foreach (object i in c)
if (i.Equals(o)) return true;
return false;
}
// 呼叫麻煩:需顯式建立陣列/集合
bool b = 1.In(new int[] { 1, 2, 3 });
bool b = "Tom".In(new string[] { "Bob", "Kitty", "Tom" });
public static bool In(this object o, params object[] values)
{
foreach (var v in values)
if (v.Equals(o)) return true;
return false;
}
// 呼叫簡潔許多
bool b1 = 1.In(1, 2, 3, 4, 5);
bool b2 = "Tom".In("Bob", "Kitty", "Tom", "Jim");
// 隱患:object 參數允許混合型別,編譯通過但邏輯錯誤
string name = "App1";
bool dangerous = "Tom".In("Bob", "Kitty", name, 3); // 不小心多打逗號,3 為 int
// 解決:泛型約束強制型別一致
public static bool In<T>(this T source, params T[] values)
{
return values.Any(v => v.Equals(source));
}
// 現在編譯器會攔截型別不匹配
// "Tom".In("Bob", "Kitty", 3); // 編譯錯誤:無法從 int 轉換為 string
public static class InExtensions
{
// 基礎版:適用小型陣列
public static bool In<T>(this T source, params T[] values)
=> values?.Any(v => EqualityComparer<T>.Default.Equals(v, source)) ?? false;
// 大集合優化:轉為 HashSet O(1) 查找
public static bool In<T>(this T source, IEnumerable<T> values)
{
if (values == null) return false;
// 閾值可調整,如 > 50 元素改用 HashSet
return values is ICollection<T> coll && coll.Count > 50
? new HashSet<T>(values).Contains(source)
: values.Contains(source);
}
// 支援自訂比較器
public static bool In<T>(this T source, IEqualityComparer<T> comparer, params T[] values)
=> values?.Any(v => comparer.Equals(v, source)) ?? false;
}
// 基本用法
if (status.In(Status.Active, Status.Pending)) DoWork();
// 字串比較忽略大小寫
if (userInput.In(StringComparer.OrdinalIgnoreCase, "yes", "y", "ok")) Confirm();
// 搭配列舉
if (dayInWeek.In(DayOfWeek.Saturday, DayOfWeek.Sunday)) IsWeekend();
// 數值範圍檢查 (配合 C# 8 範圍運算子)
if (score.In(Enumerable.Range(60, 41).ToArray())) IsPass(); // 60~100
| 版本 | 呼叫語法 | 型別安全 | 效能 | 適用場景 |
|---|---|---|---|---|
| 原版 | new[] { ... } | 無 (object) | O(n) | 示範用 |
| Params | 1, 2, 3 | 無 (object) | O(n) | 快速原型 |
| 泛型 | 1, 2, 3 | 編譯期保證 | O(n) | 一般業務 |
| 優化版 | 集合/陣列 | 編譯期保證 | O(1) 大集合 | 高頻/大數據 |
從 object 到泛型、從陣列到 IEnumerable、從線性搜尋到 HashSet 優化,In 擴展的演進過程完美詮釋了「深入想一步」的工程思維:語法糖要好吃,更要營養安全。建議將優化版收納於專案共用庫,替代冗長的 || 判斷鏈。