(为类或结构的实例建立索引)
索引器使您得以按照与数组相同的方式为类或结构实例建立索引。若要声明索引器,请使用以下方式:
[attributes] [modifiers] indexer-declarator {accessor-declarations}
indexer-declarator 采用下列形式之一:
type this [formal-index-parameter-list] type interface-type.this [formal-index-parameter-list]
formal-index-parameter 采用的形式为:
[attributes] type identifier
其中:
-
attributes(可选)
- 附加的声明性信息。有关属性和属性类的更多信息,请参见 C# 属性 。 modifiers(可选)
- 可以使用的修饰符为 new、virtual、sealed、override、abstract、extern 以及四个访问修饰符的有效组合。有关详细信息,请参见 访问修饰符 。 indexer-declarator
- 包括由索引器引入的元素 type(即 this)以及 formal-index-parameter-list。如果索引器为显式接口成员实现,则包括 interface-type。 type
- 类型名称。 interface-type
- 接口名称。 formal-index-parameter-list
- 指定索引器的参数。参数包括可选的 attributes、索引 type 和索引 identifier。必须至少指定一个参数。不允许参数修饰符 out 和 ref。 accessor-declarations
- 索引器访问器,它们指定与读写索引器元素有关的可执行语句。 identifier
- 参数名。
get 访问器
索引器的 get 访问器体与方法体类似。它返回索引器的类型。get 访问器使用与索引器相同的 formal-index-parameter-list。例如:
get
{
return myArray[index];
}
set 访问器
索引器的 set 访问器体与方法体类似。除了 value 隐式参数外,它还使用与索引器相同的 formal-index-parameter-list。例如:
set
{
myArray[index] = value;
}
备注
索引器的类型和 formal-index-parameter-list 中引用的每个类型必须至少与索引器本身一样是可访问的。有关可访问级别的更多信息,请参见访问修饰符。
索引器的签名由其形参的数量和类型组成。它不包括索引器类型或形参名。
如果在同一类中声明一个以上的索引器,则它们必须具有不同的签名。
索引器值不作为变量来分类;因此,不可能将索引器值作为 ref 或 out 参数来传递。
若要为索引器提供可由其他语言用于默认索引属性的名称,可在声明中使用 name 属性。例如:
[System.Runtime.CompilerServices.CSharp.IndexerName("MyItem")] public int this [int index] // Indexer declaration { }
此索引器将具有名称 MyItem
。如果不提供 name 属性,则默认名称为 Item
。
示例
以下示例说明如何声明私有数组字段、myArray
和索引器。通过使用索引器可直接访问实例 b[i]
。另一种使用索引器的方法是将数组声明为 public 成员并直接访问它的成员 myArray[i]
。
// cs_keyword_indexers.cs using System; class IndexerClass { private int [] myArray = new int[100]; public int this [int index] // Indexer declaration { get { // Check the index limits. if (index < 0 || index >= 100) return 0; else return myArray[index]; } set { if (!(index < 0 || index >= 100)) myArray[index] = value; } } } public class MainClass { public static void Main() { IndexerClass b = new IndexerClass(); // Call the indexer to initialize the elements #3 and #5. b[3] = 256; b[5] = 1024; for (int i=0; i<=10; i++) { Console.WriteLine("Element #{0} = {1}", i, b[i]); } } }
输出
Element #0 = 0 Element #1 = 0 Element #2 = 0 Element #3 = 256 Element #4 = 0 Element #5 = 1024 Element #6 = 0 Element #7 = 0 Element #8 = 0 Element #9 = 0 Element #10 = 0
注意,当计算索引器的访问时(例如,在 Console.Write 语句中),调用 get 访问器。因此,如果 get 访问器不存在,将发生编译时错误。
当索引器声明包含 extern
修饰符时,称该索引器为外部索引器。因为外部索引器声明不提供任何实际的实现,所以它的每个访问器声明都由一个分号组成。
下面的示例声明了一个 BitArray
类,该类实现了一个索引器,用于访问位数组中的单个位。
using System; class BitArray { int[] bits; int length; public BitArray(int length) { if (length < 0) throw new ArgumentException(); bits = new int[((length - 1) >> 5) + 1]; this.length = length; } public int Length { get { return length; } } public bool this[int index] { get { if (index < 0 || index >= length) { throw new IndexOutOfRangeException(); } return (bits[index >> 5] & 1 << index) != 0; } set { if (index < 0 || index >= length) { throw new IndexOutOfRangeException(); } if (value) { bits[index >> 5] |= 1 << index; } else { bits[index >> 5] &= ~(1 << index); } } } }
BitArray
类的实例所占的内存远少于相应的 bool[]
(这是由于前者的每个值只占一位,而后者的每个值要占一个字节),而且,它可以执行与 bool[]
相同的操作。
下面的 CountPrimes
类使用 BitArray
和经典的“筛选”算法计算 1 和给定的最大数之间质数的数目:
class CountPrimes { static int Count(int max) { BitArray flags = new BitArray(max + 1); int count = 1; for (int i = 2; i <= max; i++) { if (!flags[i]) { for (int j = i * 2; j <= max; j += i) flags[j] = true; count++; } } return count; } static void Main(string[] args) { int max = int.Parse(args[0]); int count = Count(max); Console.WriteLine("Found {0} primes between 1 and {1}", count, max); } }
请注意,访问 BitArray
的元素的语法与访问 bool[]
的元素的语法完全相同。
下列示例显示一个具有带两个参数的索引器的 26 乘 10 网格类。第一个参数必须是 A–Z 范围内的大写或小写字母,而第二个参数必须是 0–9 范围内的整数。
using System; class Grid { const int NumRows = 26; const int NumCols = 10; int[,] cells = new int[NumRows, NumCols]; public int this[char c, int col] { get { c = Char.ToUpper(c); if (c < 'A' || c > 'Z') { throw new ArgumentException(); } if (col < 0 || col >= NumCols) { throw new IndexOutOfRangeException(); } return cells[c - 'A', col]; } set { c = Char.ToUpper(c); if (c < 'A' || c > 'Z') { throw new ArgumentException(); } if (col < 0 || col >= NumCols) { throw new IndexOutOfRangeException(); } cells[c - 'A', col] = value; } } }