C# 索引器讓類別實例可用 obj[key] 存取,常被視為陣列/字典的簡化介面。但其真正威力在於:**以領域語義封裝複雜查詢邏輯**,讓呼叫端程式碼更貼近業務語言。
public class SpaceGrid
{
private readonly Dictionary<(int X, int Y, int Z), Voxel> _data = new();
// 三維座標索引器
public Voxel this[int x, int y, int z]
{
get => _data.TryGetValue((x, y, z), out var v) ? v : Voxel.Empty;
set => _data[(x, y, z)] = value;
}
// 切片索引器:固定 Z 軸取得二維平面
public Voxel[,] this[int z]
{
get
{
var slice = new Voxel[Width, Height];
for (int x = 0; x < Width; x++)
for (int y = 0; y < Height; y++)
slice[x, y] = this[x, y, z];
return slice;
}
}
}
// 使用
var grid = new SpaceGrid(100, 100, 50);
grid[10, 20, 5] = new Voxel { Density = 0.8f };
var floor5 = grid[5]; // 直接取得第 5 層平面
public class StaffDirectory
{
private readonly Dictionary _byId = new();
private readonly Dictionary _byPinyin = new(); // 拼音縮寫
private readonly Dictionary> _byDept = new();
// 依員工編號
public Employee this[string empId] => _byId.TryGetValue(empId, out var e) ? e : null;
// 依拼音縮寫 (如 "zhs" → 張三)
public Employee this[PinyinKey key] => _byPinyin.TryGetValue(key.Value, out var e) ? e : null;
// 依部門 + 職稱 (複合鍵)
public IEnumerable this[Department dept, Title title]
{
get => _byDept.TryGetValue(dept, out var list)
? list.Where(e => e.Title == title)
: Enumerable.Empty();
}
}
// 使用
var dir = new StaffDirectory();
var emp = dir["E001"]; // 編號查詢
var emp2 = dir[new PinyinKey("zhs")]; // 拼音查詢
var mgrs = dir[Department.RD, Title.Manager]; // 複合條件
public class ProductCatalog
{
private readonly List _products = new();
// 單一條件
public Product this[Func predicate]
{
get => _products.FirstOrDefault(predicate);
}
// 多條件組合 (params 陣列)
public IEnumerable this[params Func[] predicates]
{
get
{
var query = _products.AsEnumerable();
foreach (var p in predicates) query = query.Where(p);
return query;
}
}
}
// 使用
var catalog = new ProductCatalog();
var p1 = catalog[x => x.Id == "P100"]; // 單一條件
var p2 = catalog[ // 多條件 AND
x => x.Category == "Electronics",
x => x.Price < 5000,
x => x.InStock
];
索引器作為**領域介面**,內部委派給 LINQ to Objects / EF Core / Dapper:
public class OrderRepository
{
private readonly DbContext _db;
public OrderRepository(DbContext db) => _db = db;
// 對外:簡潔語義
public Order this[OrderId id] => _db.Orders.Find(id.Value);
public IEnumerable this[CustomerId cid, DateRange range] =>
_db.Orders.Where(o => o.CustomerId == cid.Value && range.Contains(o.OrderDate));
public IEnumerable this[OrderStatus status] =>
_db.Orders.Where(o => o.Status == status);
}
| 成員類型 | 語義 | 典型用法 |
|---|---|---|
| 索引器 | 「根據鍵值查找/定位」 | repo[id], grid[x,y], cache[key] |
| 屬性 | 「它的特性是…」 | order.TotalAmount, user.Name |
| 方法 | 「執行某動作/行為」 | order.Ship(), user.ResetPassword() |
| 事件 | 「當…發生時通知」 | order.Shipped += ... |
OrderId 而非 string),避免混淆。null 或拋出 KeyNotFoundException 需有明確慣例並文檔化。string 鍵值查詢用 Dictionary 或 TryGetValue 即可,無需自訂索引器。