第 8 课 · 约 12 分钟 · ← 第 7 课

集合:数组、List、Dictionary

几乎所有程序都是"装一堆东西,然后对它们做点什么"。C# 的三匹主力马覆盖其中 95%:数组(定长、最快)、List<T>(可增长)、Dictionary(按键查找)。

数组:一排格子,出生时定死数量

int[] scores = new int[3];       // 恰好 3 个槽,现在决定
scores[0] = 72;
scores[1] = 95;
scores[2] = 88;

int total = 0;
for (int i = 0; i < scores.Length; i++)   // 数组用 .Length
{
    total += scores[i];
}
Console.WriteLine("total: " + total + " count: " + scores.Length);

下标从 0 开始,最后一格是 Length - 1——越过去运行时就会收到 IndexOutOfRangeException。知道值时的短写法:int[] scores = { 72, 95, 88 };

List<T>:同一排格子,按需增长

var names = new List();
names.Add("Ada");
names.Add("Grace");
names.Add("Linus");

Console.WriteLine(names.Count);          // List 用 .Count,不是 .Length

names.RemoveAt(0);                       // 按下标删——数组做不到这个
Console.WriteLine(string.Join(", ", names));

<string> 是类型实参:这个列表装字符串,编译器强制执行。Add、Remove、Contains、IndexOf、Sort、Reverse——日常工具箱。注意这里是 .Count,数组是 .Length;搞混了也无妨,错误消息会提醒你(CS1061)。

Dictionary:没有下标——按 KEY 查

var ages = new Dictionary();   // 键是 string,值是 int
ages["Ada"] = 36;                           // 按键添加或更新
ages["Grace"] = 45;

Console.WriteLine(ages["Ada"] + ages["Grace"]);

foreach (string k in ages.Keys)             // 遍历键
{
    Console.WriteLine(k + " -> " + ages[k]);
}

if (ages.TryGetValue("Linus", out int age)) // 安全查找
{
    Console.WriteLine(age);
}
else
{
    Console.WriteLine("Linus not found");
}

一个陷阱:用 ages["Linus"] 读不存在的键会抛出 KeyNotFoundException——这正是 TryGetValue 存在的原因。它是字典版的 int.TryParse:试着查,按成败分支。

foreach 对三者通吃

int[] arr = { 72, 95, 88 };
var list = new List { 1, 2, 3 };

foreach (int x in arr)  Console.Write(x + " ");
foreach (int x in list) Console.Write(x + " ");

(字典在本引擎里需要 foreach 遍历 .Keys/.Values——成对遍历的 KeyValuePair 在路线图上。)

哪个,什么时候?

需求用为什么
固定槽位、下标运算、性能T[]最小、最快、不可增删
"一堆东西"要增要删List<T>现代 C# 的默认选择
按名字/ID 查,不按位置Dictionary<K,V>按键即时查找
只遍历一次任意 + foreach根本不需要下标

现在就练