简介:

索引器(Indexer)是类的成员之一,允许用户像操作数组那样通过索引操作类(class)或结构(struct)的实例。例如bookshelf[1] = "CLR via C#",其中bookshelfBookshelf类的一个实例,Bookshelf类实现了public string this[int i]{...}索引器。

定义方法:

类似大多数类成员的定义,包括作用域限定符、返回值类型、this关键字、索引器操作符、索引类型、索引形参名等,方法体中需要实现getter和setter中的至少一个。完整的索引器定义例如下:

与数组的索引不同,索引器中的索引可以定义为任何类型,并不仅限于数字,下例中的索引被定义为字符串类型,可以进行类似字典的操作。

类似属性的getter与setter,其可以去掉getter或setter实现只写(不常用)/只读的功能。只有getter的索引器定义例如下:

索引器重载:

类似方法的重载,索引器也可以进行重载。索引器构成重载的要素(?这里不知道该怎么说)可以是参数数量、参数类型,返回值类型不做考虑。上例中两个索引器就是定义在同一个类Bookshelf中的,可以构成重载。

接口中定义索引器:

接口中同样可以定义索引器。类似方法的定义,接口中不需要定义getter与setter的具体内容。本例中Bookshelf类继承自IContainer接口,该接口的定义如下:

IL探究:

查看上述提到Bookshelf类的IL代码,可以发现与属性类似,索引器成员自动生成了我们之前定义的getter或者setter方法,可以认为索引器也是一种语法糖,如下图所示:

其中蓝色的是第一个索引器,红色的是第二个索引器(只有getter)。

应用场景:

最简单的,对类中的数组字段进行封装,屏蔽到超出数组范围的索引访问(Bookshelf类中有体现),屏蔽不合理的数据写入(例:年龄数组元素必须为正且小于150,可以类似属性,将逻辑写在setter里)。不适用索引器对类中数组字段封装需要用到成员函数,其调用时代码没有索引器直观。

因为其形式上与属性很像(也有getter与setter,并且最终都是通过方法进行实现),两者可以在一定程度上进行替换,例如对字段age进行访问,可以通过属性实现写作people.Age,也可以通过索引器进行访问写作people["Age"]之类的。

这里可以发现索引器的一个特点:索引本身可以是一个变量,即我们可以通过改变索引变量的值来改变操作的字段。这里我们引入SwitchConsole类作进一步说明。该类字段定义如下:

SwitchConsole类包含大量bool类型的私有字段,代表该控制台上大量的开关的状态(true为开false为关)。当一次对一组开关进行操作时,可以使用索引器简化代码,如下:

索引器定义:

操作代码:

之后只需要修改switches数组内的元素即可做到修改不同的开关的状态了。当然,显然这个场景这样做定义索引器的时候需要写大量的case语句十分不便,这个需求还可以直接使用Dictionary<string,bool>来实现,具体代码恕不赘述。这里只是提供一种使用索引器的思路,之前有过Python/Perl编程经验的朋友应该对这种操作方式应该会比较熟悉。

附录:

MSDN:Indexers (C# Programming Guide) | Microsoft Docs

源码:CSharp-features-lab/Indexer/


发表评论

电子邮件地址不会被公开。 必填项已用*标注