首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 索引器進階應用:從陣列存取到領域語義封裝

     編輯:關於C#

索引器不只是「陣列語法糖」

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]; // 複合條件

案例三:委派傳遞查詢規則 (類 SQL WHERE)


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 內部實作、索引器對外暴露

索引器作為**領域介面**,內部委派給 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);
}

索引器 vs 屬性 vs 方法 vs 事件:職責分工

成員類型語義典型用法
索引器「根據鍵值查找/定位」repo[id], grid[x,y], cache[key]
屬性「它的特性是…」order.TotalAmount, user.Name
方法「執行某動作/行為」order.Ship(), user.ResetPassword()
事件「當…發生時通知」order.Shipped += ...

最佳實踐檢核表

  • ✅ 索引器應為**單一職責**:查詢/定位,不執行副作用操作。
  • ✅ 參數型別應具**領域語義** (如 OrderId 而非 string),避免混淆。
  • ✅ 回傳 null 或拋出 KeyNotFoundException 需有明確慣例並文檔化。
  • ✅ 避免過度設計:單一 string 鍵值查詢用 Dictionary 或 TryGetValue 即可,無需自訂索引器。
  • ✅ 考慮效能:索引器常被視為 O(1),若內部為 O(n) 線性搜尋,請在 XML 註解標註。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved