目录
索引器
什么是索引器
声明索引器
索引器的使用
索引器的set访问器
索引器的get访问器
索引器与属性的比较
接口中的索引器
什么是索引器:
- 索引器是一组get 和 set 访问器, 与属性类类似。
索引器和属性相同点:
- 和属性一样,索引器不用分配内存来存储。
- 索引器和属性都主要被用来访问其它数据成员, 它们与这些成员数据相关联,并可以提供读取和写入。
索引器和属性不同点:
- 属性通常操作一个数据成员。
- 索引器通常可以操作多个数据成员。
- 索引器至少要有一个参数列表
- 属性需要有名称, 而索引器在相应的位置上是 this 。
说明: 我们可以认为索引器是为类的多个数据成员提供get 和 set 的属性,通过索引器,我们可以操作许多可能的数据成员。 那么索引器本身可以是任何类型,不仅仅是数值类型。
关于索引器,需要注意的有:
- 和属性一样,索引器可以只有一个访问器,也可以两个都有。
- 索引器总是实例成员,不能声明为static。
- 和属性一样,实现get 和 set 访问器的代码不必一定非要关联到某个字段和 属性。 这段代码可以做任何事情或者什么都不做。 只要 ge t访问器返回某个指定类型的值既可。
C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作。
定义索引器的方式与定义属性有些类似,其一般形式如下:
[修饰符] 索引器类型 this[索引值类型 index]
{
get{//获得属性的代码}
set{ //设置属性的代码}
}
- 修饰符包括: public, protected, private, internal, new, virtual, sealed, override, abstract, extern.
- 索引器类型是表示将要存取的数组或集合元素的类型。
- 索引值类型表示该索引器使用哪一类型的索引来存取数组或集合元素,可以是整数,可以是字符串;this表示操作本对象的数组或集合成员,可以简单把它理解成索引器的名字,因此索引器不能具有用户定义的名称。
声明索引器语法应注意的问题:
- 索引器没有名称,在名称的位置是关键字this。
- 参数列表在方括号中间。
- 参数列表中必须至少声明一个参数。
通过索引器可以存取类的实例的数组成员,操作方法和数组相似,一般形式如下:对象名[ 索引 ]
其中索引的数据类型必须与索引器的索引类型相同。例如:
Z z=new z();
z[0]=100;
z[1]=101;
Console.WriteLine(z[0]);
C#中并不将索引器类型限制为整数。例如,可以对索引器使用字符串。通过搜索集合内的字符串并返回相应的值,可以实现此类的索引器。由于访问器可以被重载,字符串和整数版本可以共存。
class DayCollection
{
string[] days={"Sun","Mon","Tues","Wed","Thurs","Fri","Sat"};
private int GetDay(string testDay)
{
int i=0;
foreach(string day in days)
{
if(day==testDay)
return i;
i++;
}
return -1;
}
public int this[string day]
{
get{return (GetDay(day))}
}
}
static void Main(string[] args)
{
DayCollection week=new DayCollection();
Console.WriteLine("Fri:{0}",week["Fri"]);
Console.WriteLine("ABC:{0}",week["ABC"]);
}
输出结果为:
Fri:5
ABC:-1
下面看一个示例程序:
namespace Ch05Ex03
{
class RandomNum
{
int temp0;
int temp1;
int temp2;
static int temp3; //静态字段
//const int temp4; 不可以用索引器设置const字段的值,必须在声明时同时指定初始值
//static const int temp4; 不可以用索引器设置静态const字段的值
//readonly int temp4; //不可以使用索引器设置readonly 字段,只能在构造函数中设置,设置了就不能够改变
//readonly static int temp5; //不可以使用索引器设置 静态readonly 字段,需要在静态构造函数中初始化
public int this [int index] //定义索引器
{
set
{
switch(index)
{
case 0:
temp0 = value;
break;
case 1:
temp1 = value;
break;
case 2:
temp2 = value;
break;
case 3:
temp3 = value;
break;
default:
throw new ArgumentOutOfRangeException("index"); //参数超出范围异常
}
}
get
{
switch(index)
{
case 0:
return temp0;
case 1:
return temp1;
case 2:
return temp2;
case 3:
return temp3;
default:
throw new ArgumentOutOfRangeException("index"); //参数超出范围异常
}
}
}
}
class Program
{
static void Main(string[] args)
{
RandomNum pt1 = new RandomNum();
WriteLine($"首先我们输出它们的值:{pt1[0]},{pt1[1]},{pt1[2]},{pt1[3]}");
//尽管字段是私有的,通过索引器我们可以在外面设置它们的值
pt1[0] = 15; // 隐式调用set访问器
pt1[1] = 16;
pt1[2] = 99;
pt1[3] = 10;
WriteLine($"再次输出它们的值:{pt1[0]},{pt1[1]},{pt1[2]}, {pt1[3]}");
var value = pt1[0];// 隐式调用get访问器
WriteLine($"\n输出value的值:{value}");
ReadKey();
}
}
}
输出结果为:
首先我们输出它们的值:0,0,0,0
再次输出它们的值:15,16,99, 10
输出value的值:15
当索引器被用于赋值时,set访问器被调用,并接受两项数据:
- 一个隐式参数value, value 持有保存的数据。
- 一个或更多的索引参数, 表示数据应该保存到哪里。
pt1[0] = 15; // 隐式调用set访问器
- 注意: 在set访问器中的代码必须检查索引参数,以确定数据应该存在哪里,然后保存它。
- 注意: set访问器的返回类型为void。
- 注意: 它使用的参数名称和索引器[ ]声明中的名称相同。
- 注意:它有一个名称为value的隐式 参数, 值参类型 和索引值类型相同。
当使用索引器获取值时,可以通过一个或多个索引参数调用get访问器。 被索引参数指示获取哪个值。
var value = pt1[0];// 隐式调用get访问器
WriteLine($"\n输出value的值:{value}");
- 注意: get 访问器方法体内的代码必须检查索引参数,确定它表示哪个字段,并返回该字段的值。
- 注意:它使用的参数名称和索引器[ ]声明中的名称相同。
- 注意: 它返回与索引器相同类型的值。
索引器与属性都是类的成员,语法上非常相似。索引器一般用在自定义的集合类中,通过使用索引器来操作集合对象就如同使用数组一样简单;而属性可用于任何自定义类,它增强了类的字段成员的灵活性。
属 性 | 索 引 器 |
允许调用方法,如同公共数据成员 |
允许调用对象上的方法,如同对象是一个数组 |
可通过简单的名称进行访问 |
可通过索引器进行访问 |
可以为静态成员或实例成员 |
必须为实例成员 |
其get访问器没有参数 |
其get访问器具有与索引器相同的形参表 |
其set访问器包含隐式value参数 |
除了value参数外,其set访问器还具有与索引器相同的形参表 |
在接口中也可以声明索引器,接口索引器与类索引器的区别有两个:
一是接口索引器不使用修饰符;
二是接口索引器只包含访问器get或set,没有实现语句。
访问器的用途是指示索引器是可读写、只读还是只写的,如果是可读写的,访问器get或set不能同时省略;如果只读的,省略set访问器;如果是只写 的,省略get访问器。
例如:
public interface IAddress
{
string this[int index]{get;set;}
string Address{get;set;}
string Answer();
}
表示所声明的接口IAddress包含3个成员:一个索引器、一个属性和一个方法,其中,索引器是可读写的。