跳转至

索引器⚓︎

一、索引器概述⚓︎

索引器是类的特殊成员,索引器的存在允许类或结构体可以像数组一样进行索引。如:

数组的索引:

string names = new string[2];
names[0] = "tom"; // 通过索引对数组赋值
var name = names[0]; // 通过索引从数组取值

索引器:

SomeObject someObject = new SomeObject();
someObject["key"] = item; // 通过索引为某个对象的属性赋值
var item = someObject["key"]; // 通过索引获取某个对象的属性值

二、索引器的定义与调用⚓︎

01 定义索引器⚓︎

索引器使用 this 关键字定义,索引器与属性类似,在定义索引器时同样会用到 get 和 set 访问器,不同的是,访问属性不需要提供参数,而访问索引器则需要提供相应的参数。

通过访问器可以设置不同的索引器:读写索引器、只读索引器、只写索引器。

索引器定义示例1
class IndexerTest
{
   private string[] arr = new string[100];
   // 定义索引器
   public string this[int i]
   {
      get { return arr[i]; }
      set { arr[i] = value; }
   }
}
// 主程序
class Program
{
   static void Main()
   {
      var indexerTest = new IndexerTest();
      indexerTest[0] = "Hello, World";
      Console.WriteLine(indexerTest[0]);// 通过索引器访问属性
   }
}
// The example displays the following output:
// Hello, World.
索引器定义示例2
internal class Person
{
    private string name;
    private int age;
    public string this[int index]
    {
        get
        {
            switch (index)
            {
                case 0:
                    return name;
                case 1:
                    return age.ToString();
                default:
                    return "-1";
            }
        }
        set
        {
            switch (index)
            {
                case 0:
                    name = value;
                    break;
                case 1:
                    age = Int32.Parse(value);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("index error");
            }
        }
    }

    public void Speak()
    {
        Console.WriteLine("{0},{1}岁", this[0], this[1]);
    }
}
// 主程序
internal class Program
{
    private static void Main(string[] args)
    {
        Person p = new Person();
        p[0] = "Tom";
        p[1] = Convert.ToString(18);
        p.Speak();
    }
}

Note

  1. 索引器不必根据整数值进行索引,由你决定如何定义特定的查找机制。
  2. 索引器是实例成员,且索引器可被重载。
  3. 索引器可以有多个形参,例如当访问二维数组时。
  4. 通过在对象自身上使用数组表示法,允许访问对象内部集合的元素。

02 表达式主体⚓︎

索引器的 get 或 set 访问器包含一个用于返回或设置值的语句很常见。为了支持这种情况,表达式主体成员提供了一种经过简化的语法。

表达式主体简化索引器定义
class IndexerTest
{
    private string[] arr = new string[100];
    // 定义读写索引器,表达式主体
    public string this[int i]
    {
        get => arr[i];
        set => arr[i] = value;
    }
}
class Program
{
    static void Main()
    {
        var indexerTest = new IndexerTest();
        indexerTest[0] = "Hello, World";
        Console.WriteLine(indexerTest[0]);// 通过索引器访问属性
    }
}
// The example displays the following output:
//       Hello, World.

Tip

设置只读索引器时可以进一步简化:

public int this[int index] => age;

三、索引器重载⚓︎

索引器可以被重载,下面以上述示例2中的例子进行重载示范:

索引器重载
internal class Person
{
    private string name;
    private int age;

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }
    // 索引器
    public int this[int index]
    {
        get => age;
        set => age = value;
    }
    // 重载的索引器
    public string this[string index]
    {
        get => name;
        set => name = value;
    }
    public void Speak()
    {
        // 调用重载的索引器
        Console.WriteLine("{0},{1}岁", this["name"], this[0]);
    }
}

internal class IndexerOverload
{
    private static void Main(string[] args)
    {
        Person person = new Person("tom", 18);
        person.Speak();
    }
}

// Output:
// tom,18岁

四、接口中的索引器⚓︎

接口中也可以定义索引,但与类中的索引器略有不同:

  1. 接口 get/set 访问器不使用修饰符;
  2. 接口 get/set 访问器通常没有正文.

示例:

接口索引器
public interface ISomeInterface
{
    //...

    // Indexer declaration:
    string this[int index]
    {
        get;
        set;
    }
}

Tip

如果需要实现不同接口中签名相同的索引器,则需要使用接口的完全限定名进行区别。

string IIndexInterface.this[int index]{}