索引器是类或结构体提供数组式访问的正式契约,非语法糖,必须定义在class/struct内且为实例成员,不支持static、泛型参数推导,参数不限于int但需谨慎使用,性能敏感且不可滥用。

索引器不是语法糖,它是类对外提供数组式访问能力的正式契约——用错场景或忽略边界检查,运行时直接抛 IndexOutOfRangeException。
索引器必须定义在类或结构体内部,不能独立存在
很多人尝试在静态类或接口里写 this[int index],编译器会报错:CS0708: 'indexer' cannot be declared in a static class。索引器本质是实例成员,依赖 get / set 访问器绑定到具体对象状态。
- 只能出现在
class或struct定义中,且不能是static - 接口可以声明索引器签名(如
int this[int i] { get; set; }),但实现类必须提供具体逻辑 - 不支持泛型参数推导——
this是非法的,类型参数需放在类声明上[int i]
索引器参数不限于 int,但 string 和多维是最常见误用点
用 string 当索引看似方便,实则绕过编译期类型安全;多维索引(如 this[int x, int y])常被当成二维数组代理,却忘了它无法被 foreach 枚举。
- 单参数
this[int i]:最常用,适配list[5]场景,务必做i = Length检查 - 字符串索引
this[string key]:适合字典式访问,但要明确处理null或不存在的key(返回默认值 or 抛KeyNotFoundException) - 多参数索引
this[int x, int y]:C# 允许,但 LINQ 方法(如Where)无法直接作用于它,也不能用于for (var v in obj)
性能陷阱:索引器里别偷偷 new 对象或查数据库
调用 obj[123] 看似轻量,但如果内部每次执行都新建 List 或发 HTTP 请求,就会在循环中指数级放大开销。
- 避免在
get中做复杂计算、I/O、锁竞争——索引器语义是“快速取值” - 如果底层是稀疏数据(如按 ID 查用户),考虑缓存结果,或改用显式方法如
TryGetValue(int id, out User user) - 值类型索引器(如
struct Matrix的this[int i, int j])要注意装箱风险:返回int没问题,返回未初始化的ref struct会编译失败
继承与重写索引器:基类声明,子类实现,但不能用 override 关键字
索引器没有 override,只有 virtual + override 组合才生效;若基类没标 virtual,子类同签名索引器是隐藏(new),不是重写。
- 基类写
public virtual string this[int i] { get { ... } } - 子类写
public override string this[int i] { get { ... } }才能被多态调用 - 没加
virtual时,子类用new声明同名索引器,父类引用仍走父类逻辑 - 接口实现索引器时,用
public string this[int i] => _data[i];表达式体写法更简洁
真正难的不是写对语法,而是判断该不该用索引器——当访问逻辑和“位置/键”强相关、且使用者预期行为接近数组或字典时,它才成立;否则,一个带参数的普通方法更清晰、更可控。










