集合与泛型#
本篇覆盖:Action 委托、Lambda 简化、var、ArrayList、List\<T>、Dictionary、装箱拆箱。泛型深入见 泛型。
一、Action 委托类型#
有返回值 vs 无返回值委托#
| 委托类型 | 返回值 | 格式 |
|---|---|---|
| Func\<参数..., 返回值> | 有 | Func<int, bool> fn = ...; |
| Action\<参数...\> | 无 | Action<string> a = ...; |
Action 基本用法#
// 两个参数,无返回值
Action<string, string> fn = (string a, string b) =>
{
Console.WriteLine(a + b);
};
fn("无人", "生还");
// 无参无返回值
Action fn1 = () => { Console.WriteLine("无参无返回值"); };
fn1();
// 嵌套委托:Action 作为参数传入另一个 Action
Action<Action> test2 = (Action a) =>
{
Console.WriteLine("何意喂");
};
test2(fn1);
委托基础见 委托与 Lambda。
Lambda 简化写法#
// 1. 参数类型可以省略
Func<int, int, bool> fn3 = (a, b) => { return (a == b); };
// 2. 只有一个参数时,可以省略 ()
Func<int, bool> fn4 = a => { return false; };
// 3. 只有一个表达式时,省略 {} 和 return,自动返回结果
Func<int, int, bool> fn5 = (a, b) => a == b;
Console.WriteLine(fn5(1, 2)); // False
二、var 关键字#
var 不是一种类型,而是类型推断。编译器根据初始值的类型自动确定变量类型。
// var 声明的变量必须给初始值
ArrayList list = new ArrayList() { 123, 123123, 123, "红藕" };
foreach (var i in list)
{
Console.WriteLine(i); // 自动推断为 object 类型
}
// 可用在方法的返回值上
var n = fn(); // 编译器根据 fn() 的返回类型推断 n 的类型
限制:var 声明时必须初始化,且不能用于类字段、方法参数。
三、ArrayList 动态数组#
- 长度不固定,可动态增减
- 不限制存储类型(可混合存 int、string 等)
- 需要
using System.Collections
常用方法#
| 方法 | 说明 | 示例 |
|---|---|---|
Add(value) |
末尾添加一个值 | list.Add(123); |
AddRange(collection) |
追加另一个集合 | list.AddRange(list1); |
Clear() |
清空所有数据 | list.Clear(); |
Insert(index, value) |
指定位置插入 | list1.Insert(3, "起飞"); |
InsertRange(index, collection) |
指定位置插入集合 | list1.InsertRange(4, nums); |
Contains(value) |
是否包含 | list1.Contains("哈哈哈"); |
GetRange(index, count) |
截取返回新 ArrayList | list1.GetRange(2, 4); |
IndexOf(value) |
从前查找索引 | list2.IndexOf(12); |
Remove(value) |
删除第一个匹配 | list1.Remove(1); |
RemoveAt(index) |
删除指定位置 | list1.RemoveAt(0); |
RemoveRange(index, count) |
删除指定范围 | list0.RemoveRange(1, 3); |
Reverse() |
颠倒顺序 | list1.Reverse(); |
Sort() |
排序 | list0.Sort(); |
⚠️ ArrayList 存储的是
object,取值时需要拆箱,有性能开销。推荐使用泛型List\<T\>。
四、List\<T\> 泛型集合#
List\<T\> 类似于 ArrayList,但:
- 长度不固定,可动态增减
- 存储的数据类型固定(强类型),避免了类型转换开销
List<int> list1 = new List<int>() { 1, 2, 3, 4, 4 };
List<string> list2 = new List<string>() { "yuaidejiyi" };
常用方法#
| 方法 | 说明 | 示例 |
|---|---|---|
list[index] |
索引访问/赋值 | list1[0] = 999; |
Add(value) |
末尾添加 | list1.Add(1); |
Remove(value) |
删除第一个匹配值 | list1.Remove(1); |
RemoveAt(index) |
删除指定位置 | list1.RemoveAt(0); |
RemoveRange(index, count) |
删除指定范围 | list1.RemoveRange(1, 2); |
RemoveAll(predicate) |
删除所有满足条件的 | list1.RemoveAll(a => a % 2 == 0); |
AddRange(list) |
追加另一个集合 | list1.AddRange(list1); |
Count |
元素个数 | names.Count |
Contains(value) |
是否包含 | names.Contains("李四") |
List<string> names = new List<string>() { "张三", "李四", "王五", "赵六" };
Console.WriteLine(names.Count); // 4
Console.WriteLine(names.Contains("李四")); // True
names.Remove("王五");
五、Dictionary 字典#
- 通过键(Key)而非索引来访问数据
- 存储键值对:
Dictionary<Key类型, Value类型>
Dictionary<int, string> keyValues = new Dictionary<int, string>()
{
{ 1, "张三" },
{ 2, "李四" },
{ 0, "hahaha" }
};
Console.WriteLine(keyValues[1]); // 张三
keyValues[1] = "来日方长"; // 修改值
keyValues.Add(12, "王五"); // 添加新键值对
Console.WriteLine(keyValues.ContainsKey(1)); // True
Console.WriteLine(keyValues.Count); // 4
注意:添加前先
ContainsKey判断,避免重复键报错。
嵌套字典#
// 字典中存储字典
List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
list.Add(new Dictionary<string, string>()
{
{ "2026-07-20", "晚上吃啥" },
{ "2026-07-21 10", "睡了吗" }
});
Console.WriteLine(list[0]["2026-07-21 10"]); // 睡了吗
// 双层字典
Dictionary<string, Dictionary<string, string>> dict = new Dictionary<string, Dictionary<string, string>>();
六、装箱与拆箱#
| 操作 | 说明 | 示例 |
|---|---|---|
| 装箱 | 值类型 → 引用类型 | int a = 1; object b = a; |
| 拆箱 | 引用类型 → 值类型 | object c = 10; int d = (int)c; |
- object 是所有类型的基类
- 装箱/拆箱涉及类型转换,有性能开销
// 装箱:int → object
int a = 1;
object b = a;
// 拆箱:object → int
object c = 10;
int d = (int)c;
// ArrayList 中的装箱拆箱
ArrayList list = new ArrayList();
list.Add(123); // 装箱:int → object
int n = (int)list[0]; // 拆箱:object → int
list.Add("123");
// int x = (int)list[1]; // 运行时报错,不能将 string 拆箱为 int
int x = int.Parse((string)list[1]); // 用 Parse 转换
Console.WriteLine(x); // 123
七、作业练习#
1. 求 List 平均值#
List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
int sum = 0;
for (int i = 0; i < list1.Count; i++)
sum += list1[i];
int avg = sum / list1.Count;
Console.WriteLine(avg); // 3
2. 生成 10 个不重复随机数(0-9)#
List<int> list2 = new List<int>();
Random rnd = new Random();
while (list2.Count < 10)
{
int r = rnd.Next(0, 10);
if (!list2.Contains(r))
list2.Add(r);
}
3. 奇偶数分组输出#
int[] num = { 1, 3, 5, 6, 8, 100, 20, 11 };
List<int> even = new List<int>();
List<int> odd = new List<int>();
for (int i = 0; i < num.Length; i++)
{
if (num[i] % 2 == 0) even.Add(num[i]);
else odd.Add(num[i]);
}
odd.AddRange(even); // 奇数在前,偶数在后
4. 删除数组中重复的值#
string[] stringArray = { "aaa", "bbb", "aaa", "ccc", "bbb", "ddd" };
for (int i = 0; i < stringArray.Length; i++)
{
for (int j = i; j < stringArray.Length; j++)
{
if (stringArray[i] == stringArray[j] && j > i)
stringArray[j] = null;
}
}
关键知识点总结#
| 概念 | 说明 |
|---|---|
| Action\<T> | 有参数、无返回值的委托类型 |
| Func\<T> | 有返回值的委托类型,最后一个泛型参数是返回值 |
| Lambda 简化规则 | 省略参数类型 → 省略括号 → 省略大括号和 return |
| var | 类型推断关键字,根据初始值自动确定类型 |
| ArrayList | 非泛型动态数组,可混合存储任意类型 |
| List\<T> | 泛型动态数组,类型固定,性能更好 |
| Dictionary\<K,V> | 键值对集合,通过 Key 快速查找 |
| 装箱 | 值类型 → 引用类型(int → object),有性能开销 |
| 拆箱 | 引用类型 → 值类型(object → int),需显式转换 |
相关笔记#
- 泛型 — 泛型方法、泛型类、泛型约束
- 委托与 Lambda — 委托与 Lambda 基础
- 数组基础 — 定长数组(ArrayList/List 的对比对象)
- C# 数据类型 — 值类型与引用类型(装箱拆箱基础)