Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Nạp chồng toán tử [] (Indexer) trong C#

Indexer cho phép instance của class/struct được truy cập như mảng: obj[index]. Được khai báo với từ khóa this.

Cú pháp cơ bản


public class MyClass
{
    private string[] _data = new string[10];
    
    // Indexer với 1 tham số int
    public string this[int index]
    {
        get => _data[index];
        set => _data[index] = value;
    }
}

Ví dụ 1: Indexer đơn giản (int index)


public class Team
{
    private string[] _members = new string[10];
    
    public string this[int index]
    {
        get => _members[index];
        set => _members[index] = value;
    }
}

class Program
{
    static void Main()
    {
        Team team = new Team();
        team[0] = "Alice";
        team[1] = "Bob";
        team[2] = "Charlie";
        
        for (int i = 0; i < 3; i++)
            Console.WriteLine(team[i]); // Alice, Bob, Charlie
            
        Console.ReadLine();
    }
}

Ví dụ 2: Overload Indexer (Nhiều tham số, kiểu khác)


public class Matrix
{
    private int[,] _data = new int[3, 3];
    
    // Indexer 2 chiều
    public int this[int row, int col]
    {
        get => _data[row, col];
        set => _data[row, col] = value;
    }
    
    // Indexer string (tìm kiếm theo tên)
    private Dictionary _lookup = new();
    
    public int this[string name]
    {
        get => _lookup.TryGetValue(name, out int val) ? val : -1;
        set => _lookup[name] = value;
    }
}

class Program
{
    static void Main()
    {
        Matrix m = new Matrix();
        m[0, 1] = 42;
        m["score"] = 100;
        
        Console.WriteLine(m[0, 1]);    // 42
        Console.WriteLine(m["score"]); // 100
        Console.WriteLine(m["missing"]); // -1
    }
}

Ví dụ 3: Read-only Indexer (Chỉ get)


public class ReadOnlyList
{
    private readonly List _items = new();
    
    public ReadOnlyList(params string[] items) => _items.AddRange(items);
    
    // Chỉ get
    public string this[int index] => _items[index];
    
    public int Count => _items.Count;
}

Indexer trong Interface


public interface IRepository
{
    T this[int id] { get; set; }
    IEnumerable GetAll();
}

public class UserRepository : IRepository
{
    private Dictionary _users = new();
    
    public User this[int id]
    {
        get => _users.TryGetValue(id, out var u) ? u : null;
        set => _users[id] = value;
    }
    // ...
}

Best Practices

  • Indexer nên có logic validation (bounds check, null check).
  • Tránh side effects phức tạp trong getter/setter.
  • Có thể overload nhiều indexer với signature khác nhau.
  • Interface thường khai báo indexer để định nghĩa contract.
  • Tên tham số indexer nên có ý nghĩa (vd: index, key, id).

Expression-bodied Indexer (C# 7+)


public string this[int i] => _data[i]; // Read-only
public string this[int i] { get => _data[i]; set => _data[i] = value; } // Read-write