何时应该使用C#索引器?

23

我想更多地使用索引器,但我不确定什么时候应该使用它们。 在线上我找到的所有例子都使用像 MyClass IndexerClass 这样的类。

在学校系统中,例如有学生和教师,并且每个教师都有一个学生列表,他们负责管理 - 在这种情况下是否需要索引器? 为简单起见:每个学生只能属于一个教师。

10个回答

15

索引器(Indexer)是一种高度专业化的属性,它允许类(或结构)的实例像数组一样进行索引操作(属性可以是静态的,但索引器不行)。

为什么要使用索引器:

  • 与新的数据结构相比,类本身就是一种数据结构。
  • 简化的语法 - 语法糖

何时使用索引器:

  • 如果您的类需要其实例的列表(/数组)(示例1)
  • 如果您的类表示直接与您的类相关的值的列表(/数组)(示例2)

示例1:

public class Person{
    public string Name{get; set;}
    
    private Person[] _backingStore;
    public Person this[int index]
    {
        get{
            return _backingStore[index];
        }
        set{
            _backingStore[index] = value;
        }
    }
}

Person p = new Person();
p[0] = new Person(){Name = "Hassan"};
p[1] = new Person(){Name = "John Skeet"};    

例子2:

class TempratureRecord{
    private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F, 61.3F, 56.5F, 56.9F, 58.8F, 61.3F};

    public int Length{
        get { return temps.Length; }
    }

    public float this[int index]
    {
        get{
            return temps[index];
        }
        set{
            temps[index] = value;
        }
    }
}

11

这是我制作的视频:http://www.youtube.com/watch?v=HdtEQqu0yOY,以下是关于该视频的详细说明。

索引器可以使用简化的接口访问类中包含的集合。它是一种语法糖。

例如,假设您有一个客户类,其中包含地址集合。现在假设我们想通过“邮政编码”和“电话号码”获取地址集合。那么逻辑上的步骤就是创建两个重载函数,一个通过“电话号码”获取,另一个通过“邮政编码”获取。如下面的代码所示,我们定义了两个函数。

Customer Customers = new Customer();
Customers.getAddress(1001);
Customers.getAddress("9090");
如果您使用索引器,可以使用下面的代码来简化上面的代码。
Customer Customers = new Customer();
Address o = Customers[10001];
o = Customers["4320948"];

干杯。


3
您的情况需要使用索引器,可以创建一个TeachersClass类,该类封装了学生(集合)和当前教师。虽然您可以通过公开学生列表来实现相同的功能,但这个示例可以为您提供参考。
以下是代码示例:
public class TeachersClass
    {
        private List<Student> _students;

        public TeachersClass(Teacher currentTeacher, List<Student> students)
        {
            CurrentTeacher = currentTeacher;
            _students = students;
        }

        public Teacher CurrentTeacher { get; set; }

        public Student this[int studentID]
        {
            get
            {
                return (from s in _students
                        where s.Id = studentID
                        select s).First();
            }
        }   
    }

3

如果一个类代表了一组对象的列表、集合或数组,通常会使用索引器。在您的情况下,您可以提供一个索引器来提供对教师学生的基于索引的访问。


对于详细说明使索引器有意义的基于集合的方面,我给予加1的评价,但提供教师\学生示例有点“为了而为”。我认为这不是一个好的API,因为索引类型概念会渗入对象模型。 - Tim Lloyd
但是也许只有当老师/包含/学生,并且具有一些重要的自然唯一键或分组时才可以这样做?否则,老师可能只会将集合作为属性或方法返回类型。即teacher.Students [“Jones”] .FirstOrDefault()使用Students查找属性的索引器 - Jason Kleban
@uosɐſ 那位先生,那是一个糟糕的API,正好证明了我的观点。直接暴露IEnumerable<Student>有什么问题?然后只需对其运行Linq即可。 - Tim Lloyd
我同意你的观点。我的帖子并不是在回复你的时候发布的,你是在我还在写作的时候发布的 :-) 也就是说,我的Students属性是一个IEnumerable<Student> -(必须是这样,不能将命名索引作为单个类定义的一部分) - Jason Kleban

3

随机访问

如果您的数据通常按顺序访问,则可以使用枚举器。

另一方面,索引器可用于直接访问特定元素,无需特定顺序。

当然,这假设您知道要访问的元素的索引。例如,组合框始终支持两个值:向用户显示的字符串和与之相关的 ID。您可以使用组合框中所选项目的 ID 直接访问集合的索引,而无需搜索集合。

C# 中索引器的好处在于您可以对其进行重载,因此可以通过不同类型的键访问项目。


1
我记得有一次在课堂上,我遇到了一个很长的数字,其中某些数字具有特殊含义(例如,如果第三个数字是3,则表示该图表采用了特定类型的编码方式,这是一种糟糕的系统,但我并没有发明它)。
为了返回该数字的第x个数字,我做了如下操作:
protected int this[int index]
{
    get
    {
        int tempN = Number;
        if (index > 0)
        {
            tempN /= index * 10;
        }
        return tempN % 10;
    }
}

它被保护是因为另一种方法使用了它,所以它有点像一个辅助工具。当然,一个简单的 GetDigit(int a) 也可以达到同样的效果(并且更容易理解),但当时我认为使用索引器是少数几次合理的选择之一。自那以后就没有再使用过 =(。


1
简单的答案(如上所述)是当类代表/包含一组项目时,索引器将返回该集合的元素。
public Student this[int index] { ..

在更高级的情况下,您可以使用类创建默认行为,并使其看起来有点像委托,特别是当该类表示映射或进程时。例如,一个计算冰箱中啤酒冷却速率的类:

与其输入

temperature = coorsLight.CalculateFutureTemperature(time);

你可以将这个压缩成

temperature = coorsLight[time];

如果类的预期行为(和意图)是返回一个值。

1
索引器允许类或结构的实例像数组一样被索引。索引器类似于属性,但它们的访问器带有参数。
索引器使得对象能够以类似于数组的方式被索引。
    // C#: INDEXER 
using System; 
using System.Collections; 

class MyClass 
{ 
    private string []data = new string[5]; 
    public string this [int index] 
    { 
       get 
       { 
           return data[index]; 
       } 
       set 
       { 
           data[index] = value; 
       } 
    } 
}

class MyClient 
{ 
   public static void Main() 
   { 
      MyClass mc = new MyClass(); 
      mc[0] = "Rajesh"; 
      mc[1] = "A3-126"; 
      mc[2] = "Snehadara"; 
      mc[3] = "Irla"; 
      mc[4] = "Mumbai"; 
      Console.WriteLine("{0},{1},{2},{3},{4}",mc[0],mc[1],mc[2],mc[3],mc[4]); 
   } 
} 

{{链接1:代码项目}}


1
索引器是从聚合物(如数组或集合)中选择元素的一种方式。虽然我在某种程度上同意Ian Davis的观点,但我认为索引器代表的不仅仅是公共API的完善。
索引器是访问数组和表示.NET BCL中大多数集合的主要类的主要手段,实现索引器可能是为了提供处理聚合其他类型的类型时的共同体验。
由于索引器是许多BCL集合类型接口的标准部分,并且由于这些类型被广泛使用,因此当开发人员学习.NET平台时,可以合理地认为他们期望能够使用某种类型的索引器访问集合。
如果您的类型界面符合开发人员已经拥有的期望,则该类型变得更易于使用,因为开发人员不必思考。无论这些开发人员是您组织内部的还是外部的,这都是真的。
当然,有些情况确实没有索引器就没有意义,如果是这种情况,请不要实现索引器。

0

在我看来,如果你想要改进一个打包的 API,索引器可能是最好的选择 - 对于普通的业务对象而言,这并不值得花费精力。

如果你正在创建一些专门的集合,我会将其归类为改进打包的 API - 即使你将所有内容都放在一个模块中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接