List是泛型类,编译期需明确类型以确保类型安全、避免装箱拆箱;不指定类型会编译失败,.NET无非泛型List。
声明和初始化 List
时为什么必须指定类型
因为
是泛型类,编译器需要在编译期就知道元素类型,才能做类型检查、避免装箱拆箱、保证内存布局安全。不写类型(比如只写
)会编译失败,.NET 不提供非泛型的
类型(旧版
已淘汰)。
常见错误现象:
正确写法:
带初始值的写法:
预设容量(适合已知大致规模):
—— 避免多次扩容带来的内存复制开销
Add 与 AddRange 的实际性能差异在哪
每次只加一个元素,内部可能触发一次扩容判断;
接收整个
(如数组、另一个
),它会先计算总长度,一次性扩容到位,再批量拷贝 —— 这比循环调用
快得多,尤其对大量数据。
使用场景:从数据库查出 500 条记录要塞进新列表,别用
+
,直接
。
错误示范:
推荐写法:
注意:
为空或 null 时,
会抛
,需提前判空
Remove 和 RemoveAt 容易混淆的语义区别
是“按值删第一个匹配项”,返回
表示是否删成功;
是“按索引删固定位置”,越界直接抛
—— 二者完全不等价,不能互相替换。
C知道
CSDN推出的一款AI技术问答工具
下载
常见错误现象:
想删索引为 0 的元素,结果删掉了值为 0 的第一个元素(如果列表里根本没有 0,就什么也不做)。
删第 0 个位置 → 用
删值为 100 的元素 → 用
删所有值为 100 的元素 → 用
,不是反复调用
遍历时修改列表引发的 InvalidOperationException
用
遍历
时,如果在循环体内调用
、
、
等改变结构的方法,运行时会立即抛
—— 这是 .NET 的安全保护机制,防止迭代器失效后继续读脏数据。
解决办法不是加锁或 try-catch,而是换策略:
要边查边删 → 改用
倒序遍历:
要收集待删项 → 先用
或
提取,再统一
只是读取+少量修改 → 用
正序配
(索引器赋值不触发结构变更)
这个异常不会在编译时报错,只有运行到那一步才崩,容易漏测 —— 尤其在逻辑分支多、条件嵌套深的代码里,得特别留神。
ListListListArrayListThe non-generic type 'List' cannot be used with type argumentsList names = new List(); List nums = new List { 1, 2, 3 }; List buffer = new List(4096); AddAddRangeIEnumerableListAddforeachAddlist.AddRange(dbResults)foreach (var x in source) list.Add(x);list.AddRange(source);sourceAddRangeArgumentNullExceptionRemoveboolRemoveAtArgumentOutOfRangeExceptionlist.Remove(0)list.RemoveAt(0)list.Remove(100)list.RemoveAll(x => x == 100)RemoveforeachListAddRemoveClearInvalidOperationException: Collection was modifiedforfor (int i = list.Count - 1; i >= 0; i--) if (needRemove(list[i])) list.RemoveAt(i);WhereFindAllRemoveAllforlist[i] = newValue