CodeGym /课程 /C# SELF /列表: List<T>

列表: List<T>

C# SELF
第 27 级, 课程 2
可用

1. 入门

想象一下你在记购物清单。今天你要买3样东西,明天10样,后天就1样。如果你用数组,每次都得新建一个数组来装具体数量的商品。或者你干脆建个超大的数组“以防万一”,结果带着一堆空格子。听起来效率很低吧?

现在想象你有个魔法背包,你往里塞东西它自己变大,拿出来它又能缩小。你不用提前知道要装多少东西。你随便塞,背包自己适应。这就是C#里List<T>的感觉!

List<T>是个泛型集合,可以存放某种类型的一串元素。关键字是“动态”。和数组不一样,List<T>能在程序运行时自动变长。它自己管理内部容量,需要时会自动扩容。

List<T>里的T是啥?其实就是个类型参数。你创建List时,指定它要存哪种类型的数据来替换T。比如List<int>只能存整数,List<string>只能存字符串,List<double>只能存小数。这样你就不会把苹果塞进橙子清单里,对代码的稳定性和可预测性很重要。

为啥要用它?

实际项目里经常遇到你事先不知道有多少元素的情况。比如:

  • 网站上登录的用户列表。
  • 网店购物车里的商品列表。
  • 搜索结果列表。
  • 任务管理器里的任务列表(我们马上就要写这个)。

这些场景下元素数量随时变,List<T>就是我们的好帮手。

List<T>的常用方法

方法 说明 例子
Add(T item)
把元素加到列表末尾
numbers.Add(5);
Insert(int idx, T)
插入到指定位置
numbers.Insert(0, 42);
Remove(T item)
删除第一个出现的元素
numbers.Remove(100);
RemoveAt(int idx)
按索引删除元素
numbers.RemoveAt(2);
Clear()
清空列表
numbers.Clear();
Contains(T item)
判断列表里有没有某元素
numbers.Contains(10);
IndexOf(T item)
第一个出现的位置
int pos = numbers.IndexOf(42);
Count
列表里的元素个数
int n = numbers.Count;
Capacity
内部缓冲区容量
numbers.Capacity = 100;

2. 创建列表(List<T>)

来点实操!假设我们要写个简单的任务管理器。我们需要一个列表来存放要做的事。

创建新的List<T>用new,和创建别的对象一样。

怎么声明和创建List

创建列表的语法和数组很像,只不过用尖括号不是方括号:

using System.Collections.Generic;

List<int> numbers = new List<int>();

给喜欢细节的同学:
- List<int>是整数列表(int)。你也可以用string、double、自定义类等等。
- 新建后列表是空的,长度是0。

例子:我们应用的第一步

假如我们有个应用,用户输入姓名和年龄(还记得最早的课吧)。现在我们要加个功能,把多个名字存进列表,方便后续操作。

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> names = new List<string>();

        Console.WriteLine("请输入三个名字:");
        for (int i = 0; i < 3; i++)
        {
            string name = Console.ReadLine();
            names.Add(name);
        }

        Console.WriteLine("你输入了:");
        foreach (string n in names)
        {
            Console.WriteLine(n);
        }
    }
}

注意Add()。就是它让列表能动态加新元素!

还可以直接带元素创建列表!

List<string> planets = new List<string> { "水星", "金星", "地球" };

很方便,尤其你已经知道“初始阵容”的时候。测试和初始化固定数据时常用这种写法。

3. List<T>的基本操作

在玩花活之前,先把“字母表”搞明白。

添加元素:Add()

用Add()方法就像往架子上放新东西:

List<int> numbers = new List<int>();
numbers.Add(42);
numbers.Add(100);

现在里面是:[42, 100]

获取元素数量:Count

和数组不一样,列表用Count属性,不是Length:

int count = numbers.Count; // 返回2

记住:列表用Count,数组和字符串用Length。功能类似但名字不同。

按索引访问元素

两种方式,其实都一样:

int first = numbers[0]; // 42
numbers[1] = 200; // 把100换成200

注意:索引和数组一样,从0开始。只有3个元素时别去访问numbers[3]!

遍历列表元素

可以用for循环,也可以用foreach:

// 用for——需要索引时
for (int i = 0; i < numbers.Count; i++)
{
    Console.WriteLine(numbers[i]);
}

// 用foreach——不需要索引时
foreach (int number in numbers)
{
    Console.WriteLine(number);
}

foreach一般更简单直观,尤其列表很大时。
但它不能直接按索引改元素,也不能用break提前跳出,除非你用别的技巧。

按索引插入元素:Insert()

Insert()方法可以把元素插到列表中间,比如第二个位置:

numbers.Insert(1, 55); // 把55插到索引1的位置

现在numbers: [42, 55, 200]

删除元素

删除和添加一样简单:

numbers.Remove(55); // 删除第一个55
numbers.RemoveAt(0); // 删除索引0的元素
numbers.Clear(); // 清空整个列表

删除小贴士:
- 用Remove删不存在的值不会报错,列表没变化。
- Clear()后列表又变空了。

4. 有用的细节

List<T>怎么扩容

你往List<T>里加元素时,它不是每次都只加一点点空间。List<T>会提前分配一块带余量的内存(内部容量就是Capacity)。

当元素比当前容量多时,列表会分配更大的内存块(通常是原来的2倍),然后把老数据全复制过去:


加元素→还能装→还能装→还能装→
新元素装不下→分配更大的数组→复制数据→继续加

这样加元素更快,因为不是每次Add都重新分配内存,只是偶尔才扩容。

var list = new List<int>();    // Capacity = 0
list.Add(1);                   // Capacity = 4
list.Add(2);                   // Capacity = 4
list.Add(3);                   // Capacity = 4
list.Add(4);                   // Capacity = 4
list.Add(5);                   // Capacity = 8 (扩容了!)

Capacity vs. Count:有啥区别?

  • Count——实际加进列表的元素个数。
  • Capacity——内部数组的大小。
List<int> nums = new List<int>();
Console.WriteLine(nums.Count); // 0
Console.WriteLine(nums.Capacity); // 通常是0或很小

nums.Add(123);
Console.WriteLine(nums.Count); // 1
Console.WriteLine(nums.Capacity); // 现在可能比Count大

nums.Capacity = 1000; // 你知道会有很多元素时可以手动调大Capacity

大多数开发者只用Count,但如果你写高性能应用(比如游戏或数据分析),手动调Capacity有时很有用。

5. 例子

继续完善我们的迷你应用——比如让用户输入喜欢的数字,然后可以插入、删除、输出和清空列表。

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> favoriteNumbers = new List<int>();

        Console.WriteLine("请输入你喜欢的数字(每行一个,输入0结束):");
        while (true)
        {
            int num = int.Parse(Console.ReadLine());
            if (num == 0) break;
            favoriteNumbers.Add(num);
        }

        Console.WriteLine("你喜欢的数字:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }

        Console.WriteLine("\n要不要删掉第一个数字?(y/n)");
        if (Console.ReadLine().ToLower() == "y")
        {
            favoriteNumbers.RemoveAt(0);
        }

        Console.WriteLine("现在你的列表是:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }
    }
}

注意:这里用的是int.Parse。实际项目里最好用int.TryParse来校验输入,防止用户输错导致程序崩溃。

6. 新手常见的坑

很常见的一个场景:你写了个从0到List.Count的循环,但在循环里(比如foreach里)又改了列表(加或删元素)。千万别这样!老司机都叫这“遍历时修改集合”。大多数情况下你会直接遇到InvalidOperationException异常。

错误代码示例:

foreach (int n in numbers)
{
    if (n < 0)
        numbers.Remove(n); // 崩!运行时错误。
}

正确做法:要么先把要删的索引/元素收集到另一个列表里,要么用倒序的for循环。

2
任务
C# SELF, 第 27 级, 课程 2
已锁定
在 List 中操作字符串
在 List 中操作字符串
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION