一、前置基础(MVC学习前提)_核心特性_【C# 泛型入门】为什么说 List<T>是程序员的 “万能收纳盒“?避坑指南在此
目录
- 一、List<T>是什么?先看一个生活类比
- 二、List<T>基础用法:从创建到常用操作
- 1. 最简单的例子:创建一个 "整数盒子"
- 2. 进阶操作:增删改查全掌握
- 三、新手必踩的 5 个坑,附解决方案
- 坑 1:未初始化就用,直接报空引用
- 坑 2:往 List 里塞 null,取用时翻车
- 坑 3:索引越界,以为 "Count 等于最大索引"
- 坑 4:遍历同时修改集合,直接崩溃
- 坑 5:用 Contains 判断自定义对象,永远返回 false
- 四、为什么 MVC 里到处都是 List<T>?
- 互动时间
大家好,我是William_cl。今天咱们聊一个 C# 里几乎天天用,但新手容易踩坑的东西 —— 泛型集合List。如果你写代码时还在纠结 “数组长度不够用”、“存数据总担心类型错”,那这篇文章一定要看完。
一、List是什么?先看一个生活类比
你家里肯定有这样的收纳盒:
- 专门放袜子的抽屉(只装袜子,不乱)
- 专门放充电器的盒子(线再多,不会和袜子混一起)
List就像这种 “带标签的收纳盒”,就是标签,比如List是 “只装整数的盒子”,List是 “只装字符串的盒子”。
对比一下 “旧时代的盒子”: - 普通数组int[]:容量固定,装满了想多放一个都不行(比如定义int[3],最多放 3 个元素)
- 非泛型集合ArrayList:啥都能装(int、string、对象混着来),取出来时经常认错类型
而List的优势就俩字:灵活(容量自动扩)+安全(只装指定类型)。
二、List基础用法:从创建到常用操作
1. 最简单的例子:创建一个 “整数盒子”
using System;
using System.Collections.Generic; // 注意:必须引用这个命名空间class Program
{static void Main(string[] args){// 创建一个只能装int的List(标签是int)List<int> numbers = new List<int>();// 往里面加元素(Add方法)numbers.Add(10);numbers.Add(20);numbers.Add(30);// 直接打印数量(Count属性)Console.WriteLine($"当前有{numbers.Count}个元素"); // 输出:3// 访问单个元素(和数组一样用索引)Console.WriteLine("第二个元素是:" + numbers[1]); // 输出:20// 遍历所有元素(foreach最方便)Console.WriteLine("所有元素:");foreach (int num in numbers){Console.WriteLine(num);}}
}
2. 进阶操作:增删改查全掌握
// 1. 初始化时直接填数据
List<string> fruits = new List<string> { "苹果", "香蕉", "橙子" };// 2. 插入元素(在指定位置加)
fruits.Insert(1, "草莓"); // 在索引1的位置插入,结果:苹果、草莓、香蕉、橙子// 3. 删除元素(两种方式)
fruits.Remove("香蕉"); // 直接删值:苹果、草莓、橙子
fruits.RemoveAt(0); // 删索引0的元素:草莓、橙子// 4. 查找元素
bool hasOrange = fruits.Contains("橙子"); // 有没有橙子?true
int index = fruits.IndexOf("草莓"); // 草莓在哪个位置?0// 5. 清空所有元素
fruits.Clear();
Console.WriteLine(fruits.Count); // 输出:0
三、新手必踩的 5 个坑,附解决方案
坑 1:未初始化就用,直接报空引用
List<int> nums;
nums.Add(1); // 报错:未将对象引用设置到对象的实例
原因:只声明了变量,没new List<int>()创建实例,就像买了个空盒子但没拆开用。解决:声明时直接初始化:List<int> nums = new List<int>();
坑 2:往 List 里塞 null,取用时翻车
List<string> names = new List<string>();
names.Add(null); // 允许添加null
string first = names[0];
int length = first.Length; // 报错:未将对象引用设置到对象的实例
原因: List允许添加 null(除非 T 是值类型如 int),但后续操作 null 会报错。
解决: 添加前判断,或遍历前检查:
// 添加时过滤null
if (name != null) names.Add(name);// 遍历时有备无患
foreach (var n in names)
{if (n != null){Console.WriteLine(n.Length);}
}
坑 3:索引越界,以为 “Count 等于最大索引”
List<int> list = new List<int> { 1, 2, 3 };
Console.WriteLine(list[3]); // 报错:索引超出范围
原因: Count是元素总数,最大索引是Count-1(3 个元素,索引 0、1、2)。
解决: 访问前先判断:
if (index >= 0 && index < list.Count)
{// 安全访问
}
坑 4:遍历同时修改集合,直接崩溃
List<int> numbers = new List<int> { 1, 2, 3 };
foreach (int num in numbers)
{if (num == 2){numbers.Remove(num); // 报错:集合已修改,可能无法执行枚举操作}
}
原因: foreach 遍历是 “只读模式”,中途增删元素会破坏遍历状态。
解决: 用 for 循环倒序遍历(避免索引偏移):
for (int i = numbers.Count - 1; i >= 0; i--)
{if (numbers[i] == 2){numbers.RemoveAt(i); // 安全删除}
}
坑 5:用 Contains 判断自定义对象,永远返回 false
public class Person
{public string Name { get; set; }public Person(string name) { Name = name; }
}// 测试代码
List<Person> people = new List<Person>();
people.Add(new Person("张三"));// 想判断是否有"张三"
bool hasZhang = people.Contains(new Person("张三")); // 结果:false
原因: Contains默认比较 “对象地址”(引用类型),两个new Person(“张三”)是不同对象,地址不同。
解决: 让 Person 类实现IEquatable接口,自定义比较规则:
public class Person : IEquatable<Person>
{public string Name { get; set; }public Person(string name) { Name = name; }// 自定义比较逻辑:只要Name相同就认为相等public bool Equals(Person other){return other != null && Name == other.Name;}
}
// 此时再调用Contains就会返回true了
四、为什么 MVC 里到处都是 List?
在 MVC 开发中,List简直是 “刚需”:
- 控制器(Controller)从数据库查数据,用List存商品列表
- 视图(View)接收List,用 foreach 遍历显示用户表格
- 模型(Model)里的集合属性,几乎都是List(如public List Orders { get; set; })
它就像 MVC 各层之间的 “数据传送带”,安全又高效。
互动时间
你在使用List时踩过哪些奇葩的坑?有没有什么提高效率的小技巧(比如Capacity预分配容量)?欢迎在评论区分享,点赞最高的评论送我整理的《C# 集合操作手册》一份~
下一期咱们聊 LINQ,看看怎么用一行代码搞定 List 的复杂查询,不见不散!