Indexer (เรียกว่า this[]) ช่วยให้ Object ใช้ Syntax แบบ Array ได้ obj[index] สามารถ Overload ได้หลาย Signature
Syntax พื้นฐาน
public class MyCollection
{
private string[] _data = new string[10];
// Indexer แบบ Integer
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
ตัวอย่างที่ 1: Basic Integer Indexer
public class Team
{
private string[] _members = new string[10];
public string this[int index]
{
get => _members[index];
set => _members[index] = value;
}
}
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
}
ตัวอย่างที่ 2: Overload Indexer (Multiple Parameters/Types)
public class Matrix
{
private double[,] _data;
public Matrix(int rows, int cols)
{
_data = new double[rows, cols];
}
// Indexer 2 Parameters (Row, Col)
public double this[int row, int col]
{
get => _data[row, col];
set => _data[row, col] = value;
}
// Indexer String (Named Access)
public double this[string name]
{
get => name switch
{
"rows" => _data.GetLength(0),
"cols" => _data.GetLength(1),
_ => throw new ArgumentException("Invalid name")
};
}
}
static void Main()
{
Matrix m = new Matrix(3, 4);
m[0, 0] = 1.5;
m[1, 2] = 2.5;
Console.WriteLine(m[0, 0]); // 1.5
Console.WriteLine(m["rows"]); // 3
Console.WriteLine(m["cols"]); // 4
}
ตัวอย่างที่ 3: Dictionary-like Indexer (String Key)
public class Settings
{
private readonly Dictionary _values = new();
public string this[string key]
{
get => _values.TryGetValue(key, out var v) ? v : null;
set => _values[key] = value;
}
// Read-only Indexer (Expression-bodied)
public int Count => _values.Count;
}
static void Main()
{
Settings settings = new Settings();
settings["theme"] = "dark";
settings["lang"] = "th";
Console.WriteLine(settings["theme"]); // dark
Console.WriteLine(settings["lang"]); // th
Console.WriteLine(settings["missing"]); // null
}
ข้อจำกัดและกฎ
- Indexer ต้องเป็น
instanceMember (ไม่ใช่ Static) - ชื่อต้องเป็น
thisเสมอ - ต้องมีอย่างน้อย 1 Parameter
- Overload ได้โดย Parameter Types/Count ต่างกัน
- ไม่สามารถใช้
ref,out,inParameters - Interface สามารถประกาศ Indexer ได้
Interface Indexer
public interface IRepository
{
T this[int id] { get; set; }
T this[string key] { get; }
}
public class UserRepository : IRepository
{
private Dictionary _byId = new();
private Dictionary _byEmail = new();
public User this[int id]
{
get => _byId[id];
set => _byId[id] = value;
}
public User this[string email]
{
get => _byEmail.TryGetValue(email, out var u) ? u : null;
}
}
Pattern Matching Indexer (C# 9+)
public class FlexibleIndexer
{
private Dictionary _data = new();
public object this[object key] => key switch
{
int i => _data[$"int:{i}"],
string s => _data[s],
Guid g => _data[$"guid:{g}"],
_ => throw new ArgumentException("Unsupported key type")
};
}
Best Practices
- Validate Index/Key (Throw
ArgumentOutOfRangeExceptionหรือKeyNotFoundException) - Implement
IEnumerable<T>หากเป็น Collection - Consider
TryGetValuePattern สำหรับ Safe Access - Document Expected Key Types/Ranges