索引器 3个月前

编程语言
913
索引器

索引器允许类或结构的实例就像数组一样进行索引。 无需显式指定类型或实例成员,即可设置或检索索引值。 索引器类似于属性),不同之处在于它们的访问器需要使用参数。

以下示例定义了一个泛型类,其中包含用于赋值和检索值的简单get和 set访问器方法。 Program 类创建了此类的一个实例,用于存储字符串。

using System;

class SampleCollection<T>
{
   // Declare an array to store the data elements.
   private T[] arr = new T[100];

   // Define the indexer to allow client code to use [] notation.
   public T this[int i]
   {
      get { return arr[i]; }
      set { arr[i] = value; }
   }
}

class Program
{
   static void Main()
   {
      var stringCollection = new SampleCollection<string>();
      stringCollection[0] = "Hello, World";
      Console.WriteLine(stringCollection[0]);
   }
}
// The example displays the following output:
//       Hello, World.

表达式主体定义

索引器的 get 或 set 访问器包含一个用于返回或设置值的语句很常见。 为了支持这种情况,表达式主体成员提供了一种经过简化的语法。 自 C# 6 起,可以表达式主体成员的形式实现只读索引器,如以下示例所示。

using System;

class SampleCollection<T>
{
   // Declare an array to store the data elements.
   private T[] arr = new T[100];
   int nextIndex = 0;

   // Define the indexer to allow client code to use [] notation.
   public T this[int i] => arr[i];

   public void Add(T value)
   {
      if (nextIndex >= arr.Length)
         throw new IndexOutOfRangeException($"The collection can hold only {arr.Length} elements.");
      arr[nextIndex++] = value;
   }
}

class Program
{
   static void Main()
   {
      var stringCollection = new SampleCollection<string>();
      stringCollection.Add("Hello, World");
      System.Console.WriteLine(stringCollection[0]);
   }
}
// The example displays the following output:
//       Hello, World.

请注意,=> 引入了表达式主体,并未使用 get 关键字。

自 C# 7.0 起,get 和 set 访问器均可作为表达式主体成员实现。 在这种情况下,必须使用 getset 关键字。 例如:

using System;

class SampleCollection<T>
{
   // Declare an array to store the data elements.
   private T[] arr = new T[100];

   // Define the indexer to allow client code to use [] notation.
   public T this[int i]
   {
      get => arr[i];
      set => arr[i] = value;
   }
}

class Program
{
   static void Main()
   {
      var stringCollection = new SampleCollection<string>();
      stringCollection[0] = "Hello, World.";
      Console.WriteLine(stringCollection[0]);
   }
}
// The example displays the following output:
//       Hello, World.

索引器概述

  • 使用索引器可以用类似于数组的方式为对象建立索引。
  • get 取值函数返回值。 set 取值函数分配值。
  • this关键字用于定义索引器。
  • value 关键字用于定义由 set 访问器分配的值。
  • 索引器不必根据整数值进行索引;由你决定如何定义特定的查找机制。
  • 索引器可被重载。
  • 索引器可以有多个形参,例如当访问二维数组时。

索引器的使用

索引器使你可从语法上方便地创建类、结构或接口,以便客户端应用程序可以像访问数组一样访问它们。 编译器将生成一个 Item 属性(或者如果存在 IndexerNameAttribute,也可以生成一个命名属性)和适当的访问器方法。 在主要目标是封装内部集合或数组的类型中,常常要实现索引器。 例如,假设有一个类 TempRecord,它表示 24 小时的周期内在 10 个不同时间点所记录的温度(单位为华氏度)。 此类包含一个 float[] 类型的数组 temps,用于存储温度值。 通过在此类中实现索引器,客户端可采用 float temp = tempRecord 的形式(而非 float temp = tempRecord.temps)访问 TempRecord 实例中的温度。 索引器表示法不但简化了客户端应用程序的语法;还使类及其目标更容易直观地为其它开发者所理解。

若要在类或结构上声明索引器,请使用 this 关键字,如以下示例所示:

// Indexer declaration
public int this[int index]
{
    // get and set accessors
}

通过声明索引器,可自动在对象上生成一个名为 Item 的属性。 无法从实例成员访问表达式直接访问 Item 属性。 此外,如果通过索引器向对象添加自己的 Item 属性,则将收到 CS0102 编译器错误。 要避免此错误,请使用 IndexerNameAttribute 来重命名索引器,详细信息如下所示。

下面的示例声明了存储星期几的类。 get 访问器采用字符串(星期几)并返回对应的整数。 例如,“Sunday”返回 0,“Monday”返回 1,依此类推。

// Using a string as an indexer value
class DayCollection
{
    string[] days = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"];

    // Indexer with only a get accessor with the expression-bodied definition:
    public int this[string day] => FindDayIndex(day);

    private int FindDayIndex(string day)
    {
        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == day)
            {
                return j;
            }
        }

        throw new ArgumentOutOfRangeException(
            nameof(day),
            $"Day {day} is not supported.\nDay input must be in the form \"Sun\", \"Mon\", etc");
    }
}

下面的示例声明了使用 System.DayOfWeek 存储星期几的类。 get 访问器采用 DayOfWeek(表示星期几的值)并返回对应的整数。 例如,DayOfWeek.Sunday 返回 0,DayOfWeek.Monday 返回 1,依此类推。

using Day = System.DayOfWeek;

class DayOfWeekCollection
{
    Day[] days =
    [
        Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday,
        Day.Thursday, Day.Friday, Day.Saturday
    ];

    // Indexer with only a get accessor with the expression-bodied definition:
    public int this[Day day] => FindDayIndex(day);

    private int FindDayIndex(Day day)
    {
        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == day)
            {
                return j;
            }
        }
        throw new ArgumentOutOfRangeException(
            nameof(day),
            $"Day {day} is not supported.\nDay input must be a defined System.DayOfWeek value.");
    }
}

更多实例可参考官方文档

索引器和属性

索引器与属性相似。 除下表所示的差别外,对属性访问器定义的所有规则也适用于索引器访问器。

索引器与属性相似。 除下表所示的差别外,对属性访问器定义的所有规则也适用于索引器访问器。

Property 索引器
允许以将方法视作公共数据成员的方式调用方法。 通过在对象自身上使用数组表示法,允许访问对象内部集合的元素。
通过简单名称访问。 通过索引访问。
可为静态成员或实例成员。 必须是实例成员。
属性的 get 访问器没有任何参数 索引器的get访问器具有与索引器相同的形参列表
属性的 set访问器包含隐式 value 参数。 索引器的 set 访问器具有与索引器相同的形参列表,value 参数也是如此。
通过自动实现的属性支持简短语法。 支持仅使用索引器的 expression-bodied 成员。
image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2223247
累计阅读

热门教程文档

Golang
23小节
Rust
84小节
Lua
21小节
Maven
5小节
React
18小节