前两天刚刚学习完了属性,这两天又搂完了索引器,发现两者非常的相似,但是相似之外还有一些不同之处。今天就来总结一下索引器--Indexers
索引器的作用及格式
索引器的作用就是能够使类或者结构体的实例对象像数组一样使用下标的方式访问集合对象。索引器的书写格式和属性非常的类似,像是一个带有参数的属性,但是属性名只能使用this关键字,并且指定了索引类型,下面看一个简单的例子:
class MyClass{ int[] numInts = new int[10];//定义一个数组 public int this[int index]{ get { return numInts[index]; } set { numInts[index] = value; } } } class Program { static void Main(string[] args) { MyClass myClass = new myClass(); myClass[0] = 1; myClass[1] = 2; int num = myClass[1]; } }
在这个例子中,myClass通过get访问器获取numInts中的值,通过set访问器将值传递给value进行赋值,这是最简单的操作。但其实在get和set访问器中还可以进行一些条件的判断,比如在get访问器中判断下标是否越界;在set访问器中判断传值是否超出限定范围等等,能做的操作太多了。
只读&只写索引器的实现
上面说过,索引器与属性非常的相似都具有一对访问器,只是访问器接收的参数有所不同。既然拥有类似的访问器,那么只读或者只写功能的索引器与只读或者只写功能的属性,也是差不多的,下面具体阐述一下。 在之前的属性文章的说到过属性的只读或者只写有两种实现方式:
-
隐藏getter或者setter
-
给getter或者setter添加private访问修饰符 这里同样适用于索引器,只不过有以下几点需要注意:
-
通过隐藏getter来实现只读索引器的方式,只能在类中实现,结构体中的索引器不能隐藏getter
-
通过给getter添加private访问修饰符实现只读索引器也只能在类中实现,结构体中getter必须能被外界访问到
-
使用添加private访问修饰符的方式来是实现只读或者只写索引器时,getter和setter必须同时存在,缺一不可。 下面使用两种方式分别实现只读索引器:
class MyClass { private int[] nums = new []{ 1, 2, 3, 4, 5, 6, 7}; public int this[int index]//通过添加private实现只写索引器 { get{ return this.nums[index]; } private set { this.nums[index] = value; } } } class MyClass { private int[] nums = new []{ 1, 2, 3, 4, 5, 6, 7}; public int this[int index]//通过隐藏setter实现只读索引器 { get{ return this.nums[index]; } } }
索引器在接口中的使用
接口中能够声明的类型只有四种,其中就包含索引器。在接口中,索引器的使用也和属性大抵相似,getter和setter同样没有方法体,只用";"结尾。也可以通过隐藏getter或者setter来定义只读或者只写索引器,具体在接口中的使用如下:
interface ITestFace { int this[int index] { get; set; } }
同属性一样,派生类在实现索引器的时候也有两种选择:
-
可以为索引器添加virtual关键字,使后续的派生类能够进行重写
class Test2:ITestFace { private int[] count = new[] { 1, 2, 3, 4}; public virtual int this[int index] { get => count[index]; set => count[index] = value; } } class Test1:Test2 { private int[] count = new[] { 0,0,0,0 }; public override int this[int index] { get { return this.count[index]; } } } class Program { static void Main(string[] args) { Test2 Test1 = new Test1(); Console.WriteLine(Test1[1]); } } 0 请按任意键继续. . .
-
直接在索引器前添加接口名称,删除访问修饰符,进行显示接口实现
class Test2:ITestFace { private int[] count = new[] { 1, 2, 3, 4}; int ITestFace.this[int index] { get => count[index]; set => count[index] = value; } } class Program { static void Main(string[] args) { ITestFace tf = new Test2(); Console.WriteLine(tf[1]); } } 2 请按任意键继续. . .
使用显示接口实现的形式,索引器不属于派生类所有,只能被对应接口类型的派生类实例对象所使用。
索引器的其他使用方式
以上用到的索引器都是只包含一个索引值,但其实索引器的所引致可以包含多个,根据自己的需求来使用,这里就不过多介绍了,需要的可以自行Google或者百度。下面介绍一下如何在索引器中使用表达式主体定义。 表达式主体定义和lambda表达式很像,概念什么的这里就略去了,直接进入主题,在C#6当中,如果索引器只读,且get访问器只有一条语句,那么就可以使用表达式主体定义的方式进行书写,更加简洁:
class MyClass2 { private int[] nums = new []{ 1, 2, 3, 4, 5, 6, 7}; public int this[int index] => this.nums[index]; }
这种方式只适用于只读索引器,但是在C#7当中,还有另外一种使用表达式主体定义的方式,来简便的书写索引器,如下所示:
class MyClass3 { private int[] nums = new []{ 1, 2, 3, 4, 5, 6, 7}; public int this[int index] { get=>this.nums[index]; set=> nums[index] = value; } }
以上,就是关于索引器的一些内容,不足之处还请指教,下面列出一些使用索引器的注意事项,供大家使用时参考:
-
通过索引器传递进来的值会传递给value变量,value的类型必须与索引器的类型相同
-
索引器不能作为ref或者out参数使用,数组可以
-
索引器只属于对象,不能使用static进行修饰
-
结构体中也可以使用属性,但是使用时结构体需要使用关键字new进行初始化,因为索引器只属于对象
-
索引器和属性很相似,属于有参的属性,使类或者结构体可以访问像数组一下访问数据
-
使用索引器获取数据或者修改数据,接收或者传递的值的类型必须与索引器的类型相同
-
索引器和属性相同,也可以通过隐藏get或者set访问器来实现只读索引器或者只写索引器,但是在结构体中必须保留get访问器,类中可以选择性的隐藏
-
索引器的只读或者只写也可以通过给get或者set访问器添加合适的访问修饰符private来实现,但是在结构体中get访问器不能设为私有的或者被保护的,只能为public类型的