跳转至

集合与泛型#

本篇覆盖: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
ArrayList list = new ArrayList();
ArrayList list1 = new ArrayList() { "哈哈哈", 123, 12, 123 };

常用方法#

方法 说明 示例
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&lt;Key类型, Value类型&gt;
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),需显式转换

相关笔记#