AddRange 是合并两个 List 的最直接方法,原地追加、类型必须一致、不去重不排序;Union 用于去重合并并返回新序列;Concat 链式调用适合需筛选排序的场景;避免 list1 = list1.Concat(list2).ToList() 这类危险赋值。

用 AddRange 合并两个 List 最直接
想把 list2 的所有元素加到 list1 末尾,AddRange 是最自然的选择。它原地修改,不创建新对象,性能好、语义清。
- 必须确保两个
List类型一致,比如都是List;类型不同会编译报错CS1503 -
AddRange不去重、不排序,就是纯追加,适合“日志拼接”“分页数据累加”这类场景 - 如果
list1容量不足,内部数组会自动扩容,可能触发一次内存复制——高频合并时可提前用list1.Capacity += list2.Count避免反复扩容
示例:
list1.AddRange(list2);
需要新集合且去重?别手写循环,用 Union
Union 是 IEnumerable 扩展方法,返回去重后的新序列。它底层用 HashSet 判重,比手动 Contains 查找快得多。
- 结果是
IEnumerable,如需List得显式调用.ToList() - 默认用
T的Equals和GetHashCode,自定义类要重写这两个方法,否则去重失效 - 顺序保留左操作数(第一个集合)的首次出现位置,
list1.Union(list2)中list1的元素优先
示例:
var result = list1.Union(list2).ToList();
合并后要排序或筛选?别先合再处理,链式调用更高效
用 LINQ 链式操作,避免中间集合分配。比如合并 + 升序 + 去空字符串,一气呵成比分开写三步省内存、少遍历。
-
Concat比Union更轻量,不做去重,也不要求类型有IEquatable实现 - 排序放在最后一步(
OrderBy),避免在未合并完的数据上重复排序 - 如果
list1和list2本身已有序,用Enumerable.Merge(需引入System.Linq扩展)比Concat().OrderBy()快一个数量级
示例:
var result = list1.Concat(list2).Where(x => !string.IsNullOrEmpty(x)).OrderBy(x => x).ToList();
list1 = list1.Concat(list2).ToList() 这种写法很危险
表面看是“合并赋值”,实际每次执行都新建一个 List,原 list1 引用丢失。如果其他地方还持有旧引用,数据就不同步了。
- 常见于事件回调或 UI 数据绑定场景:UI 绑定的是旧
List,你却换了新对象,界面不刷新 - 如果
list1是类字段,这种写法还会破坏封装性,外部无法感知变更 - 真要替换,明确用
Clear()+AddRange(),或者暴露ReplaceWith(IEnumerable方法控制逻辑)
真正安全的替换写法:
list1.Clear();<br>list1.AddRange(list2);
合并操作看着简单,但类型匹配、引用语义、内存分配这三点,线上出过太多隐蔽问题。尤其当 List 被多个模块共享时,动不动就换引用,比数据错乱还难查。










