一起探索索引器的奥秘吧
索引器
(indexer)
C#
语言一个最令人感兴趣的地方就是类的索引器(indexer)。简单说来,所谓索引器就是一类特殊的属性,通过它们你就可以像引用数组一样引用自己的类。这就说明这一功能在创建集合类的场合特别有用,而在其他某些情况下,比如处理大型文件或者抽象某些有限资源等,能让类具有类似数组的行为当然也是非常有用的。
索引器允许类或结构的实例按照与数组相同的方式进行索引。索引器类似于属性,不同之处在于它们的访问器采用参数。它可以使得像数组那样对对象使用下标。它提供了通过索引方式方便地访问类的数据信息的方法,那么
首先让我们概述下属性这个概念以便了解些必要的背景知识。
属性 (
property
)
:
所谓属性方法其实就是特殊的类成员,它实现了对私有类域的受控访问。在C#语言中有两种属性方法,其一是get,通过它可以返回私有域的值,其二是set,通过它就可以设置私有域的值。比如说,以下面的代码为例,其间创建了一个FirstName属性,由它控制对私有类成员firstname的访问:
class Person
{
private string firstname;
public string FirstName
{
get { return firstname; }
set { firstname = value; }
}
}
属性声明可以如下编码
:
Person p = new Person();
p.FirstName = "Lamont";
Console.WriteLine(p.FirstName);
这样看来属性声明倒更像是域声明,只不过它还声明了两个特殊的成员,MSDN说法就是所谓的访问函数(accessor)。当某一表达式的右边调用属性或者属性用作其他子程序(或者函数)的参数时即会调用get访问函数。反之,当表达式左边调用属性并且通过隐式传递value参数设置私有域值的情况下就会调用set访问函数。你可以创建只读属性,方法是省略set访问函数,这样任何设置属性的尝试都会产生编译错误。
要声明类或结构上的索引器,要使用
this
关键字,例如:
public int this[int index] //
声明索引器
{
// get and set
访问
}
索引器的修饰符有:
new
、
public
、
protected
、
internal
、
private
、
virtual
、
sealed
、
override
、
abstract
和
extern
。当索引器声明包含
extern
修饰符时,称该索引器为外部索引器。因为外部索引器声明不提供任何实际的实现,所以它的每个访问器声明都由一个分号组成。
索引器的签名由其形参的数量和类型组成。它不包括索引器类型或形参名。如果在同一类中声明一个以上的索引器,则它们必须具有不同的签名。
索引器值不归类为变量;因此,不能将索引器值作为
ref
或
out
参数来传递。
下面用一个例子来说明如何声明和使用索引器。
在本示例中,定义了一个
泛型
类,并为其提供了简单的
get
和
set
访问器方法(作为分配和检索值的方法)。
Program
类为存储字符串创建了此类的一个实例。代码如下:
class SampleCollection<T>
{
private T[] arr = new T[100];
public T this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
下面是如何使用上述代码实现的索引器,具体代码示例如下:
class Program
{
static void Main (string[] args)
{
SampleCollection<string> s = new SampleCollection<string>();
s[0] = "
索引器的使用"
;
System.Console.WriteLine(s[0]);
}
}
C#
并不将索引类型限制为整数。例如,对索引器使用字符串可能是有用的。通过搜索集合内的字符串并返回相应的值,可以实现此类的索引器。如下所示:
using
System;
using
System.Collections;
;
class IndexClass
{
private Hashtable ht = new Hashtable();
public object this[object key]
{
get { return ht[key]; }
set { ht[key] = value; }
}
}
下面再谈谈属性与索引器的差别:
类的每一个属性都必须拥有唯一的名称,而类里定义的每一个索引器都必须拥有唯一的签名(signature)或者参数列表(这样就可以实现索引器重载)。属性可以是static(静态的)而索引器则必须是实例成员。为索引器定义的访问函数可以访问传递给索引器的参数,而属性访问函数则没有参数。
扩展:接口
类似数组的行为常受到程序实现者的喜爱,所以你还可以为接口定义索引器,IList和 IDictionary集合接口都声明了索引器以便访问其存储的项目。
在为接口声明索引器的时候,记住声明只是表示索引器的存在。你只需要提供恰当的访问函数即可,不必包括范围修饰符。以下代码把索引器声明为接口IImplementMe的一部分:
interface IImplementMe {
string this[int index]
{
get;
set;
}
}
相应实现的类则必须为IimplementMe的索引器具体定义get和set访问函数。
先写到这里,也只能理解到这一步了,有不足的地方希望能够得到大家的批评指正。