CodeGym /课程 /C# SELF /按索引访问的契约: IList<T>

按索引访问的契约: IList<T>

C# SELF
第 28 级, 课程 3
可用

1. 引言

想象一下:你有个集合……你想快速拿到第三个、第七个,或者说第零个元素。或者想把它们换个位置。在数组里这很简单——直接用索引(array[3])。那集合呢?不是所有集合都能随便用索引!

这时候IList<T>接口就登场了——它是个通用契约,要求集合必须支持按索引操作元素。简单说:你有个实现了IList<T>的集合——你就可以像数组那样用索引访问和修改它的元素。

类比:
想想图书馆的卡片:每本书在书架上都有自己的编号,你随时可以去拿“第三本”书。支持IList<T>的集合就是这么干的。

2. IList<T>的整体结构和方法

IList<T>接口是很多集合的主角。它继承自ICollection<T>(而它又继承自IEnumerable<T>,这样你就能用循环遍历集合),并且加上了最重要的:索引操作。

接口继承结构图:


IEnumerable<T>
      ▲
      │
ICollection<T>
      ▲
      │
  IList<T>
.NET集合接口的继承关系

IList<T>接口的主要成员

成员 作用
T this[int index] { get; set; }
按索引获取或设置元素
int IndexOf(T item)
查找元素第一次出现的索引
void Insert(int index, T item)
在指定位置插入元素
void RemoveAt(int index)
按索引删除元素

其他成员,比如Add、Remove、Clear、Contains,都是从ICollection<T>接口来的。

核心亮点:索引器

IList<T>最酷的地方就是有索引器。这就是语法糖,让你可以这样写:


var myList = new List<int> { 10, 20, 30 };
int secondValue = myList[1]; // 得到20
myList[2] = 42;              // 改第三个元素

3. 哪些集合实现了IList<T>

在.NET标准库里,很多常见的数据结构都支持IList<T>接口。来看看最常用的几个:

集合 支持索引 说明
List<T>
是 动态数组
T[]
是 普通数组支持索引
BindingList<T>
是 用于数据绑定
ObservableCollection<T>
是 带通知的列表
Collection<T>
是 集合的基类

注意:

LinkedList<T>
和
HashSet<T>
不实现 IList<T>,因为它们没有快速索引(对, LinkedList<T>没有 list[5]!)。

4. IList<T>的用法示例

按索引获取和设置


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        IList<string> fruits = new List<string> { "苹果", "香蕉", "梨" };

        // 获取第二个元素
        string fruit = fruits[1];
        Console.WriteLine(fruit); // 香蕉

        // 替换第三个元素
        fruits[2] = "橙子";
        Console.WriteLine(fruits[2]); // 橙子
    }
}

按索引插入和删除


fruits.Insert(1, "猕猴桃");    // 在第二个位置插入“猕猴桃”
// 列表现在是:"苹果", "猕猴桃", "香蕉", "橙子"

fruits.RemoveAt(0);          // 删除第一个元素("苹果")
// 列表现在是:"猕猴桃", "香蕉", "橙子"

查找元素的索引


int index = fruits.IndexOf("橙子"); // 返回索引(2),找不到就-1
if (index != -1)
    Console.WriteLine("橙子在位置:" + index);
else
    Console.WriteLine("橙子没找到");

5. 实现细节和常见错误

用IList<T>时很容易踩坑,尤其是忘了索引从零开始,集合长度就是当前元素数。

比如,试图访问不存在的元素:


Console.WriteLine(fruits[100]); // IndexOutOfRangeException!

C#里的索引就像母鸡下蛋:从零开始,不是从一。如果列表有4个元素,最后一个索引是3。

还要记住,不是所有IList<T>实现都一样快。比如数组和List<T>按索引访问是瞬间的(O(1)),但如果你用链表实现自己的集合然后强行加上IList<T>,那操作可能会很慢。标准库不会这么干。

还有一点:如果你把数组当作IList<T>用,可以改元素,但不能改数组长度。对数组用Add、Remove、Insert这些方法会抛出NotSupportedException。


int[] myArray = { 1, 2, 3 };
IList<int> listView = myArray; // 向上转型

listView[0] = 42; // 可以!
listView.Add(99); // 会抛出NotSupportedException

6. 实际应用和意义

在真实项目里,几乎一半的集合都是实现了IList<T>的,因为你可以方便地按编号访问、修改、插入和删除元素。比如:

  • WPF或WinForms里的ViewModel接口属性,UI元素列表绑定用的。
  • 实现排序、查找、换位等算法时,需要按索引访问。
  • 做数据导入/导出模块,处理动态对象列表。

面试时,问IEnumerable<T>、ICollection<T>和IList<T>的区别是经典题。你只要知道每一层干嘛的,就能自信地告诉面试官为什么HashSet<T>不实现IList<T>(因为唯一性比顺序和索引更重要!)。

2
任务
C# SELF, 第 28 级, 课程 3
已锁定
使用 Insert 和 IndexOf 方法
使用 Insert 和 IndexOf 方法
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION