linq中 List<T>.ForEach() 与 的 Select() 方法区别——CAD c#二次开发
1. 核心区别
List<T>.ForEach(Action<T> action)
- 作用:对列表中的每个元素执行指定操作(副作用),例如修改元素属性。
- 返回值:
void
(无返回值)。 - 执行时机:立即执行。
- 示例:
list.ForEach(item => item.ColorIndex = 1); // 直接修改原列表元素
Enumerable.Select(Func<T, TResult> selector)
- 作用:将集合中的每个元素映射为新值,生成一个新的序列。
- 返回值:
IEnumerable<TResult>
(延迟执行的迭代器)。 - 执行时机:延迟执行(调用
ToList()
、foreach
等终端操作时才执行)。 - 示例:
var newList = list.Select(item => {item.ColorIndex = 1; // 修改原元素return item; // 返回修改后的元素(但也可以返回新对象) }).ToList();
2. 是否可以替换?
场景 1:仅修改原集合元素(无返回值需求)
ForEach
更合适,代码更简洁:list.ForEach(item => item.ColorIndex = 1); // 直接修改,无返回值
场景 2:需要生成新集合(保留原集合不变)
- 必须用
Select
,因为ForEach
无法返回新集合: -
var newList = list.Select(item => {var clone = item.Clone(); // 克隆原对象clone.ColorIndex = 1; // 修改克隆对象return clone; // 返回新对象,原集合不变 }).ToList();
3. 关键差异对比表
-
特性 List<T>.ForEach()
Enumerable.Select()
核心用途 对元素执行副作用(如修改属性) 映射元素生成新集合 返回值 void
(无返回值)IEnumerable<TResult>
(新序列)是否修改原集合 直接修改原集合元素 不修改原集合(可选择返回新对象) 延迟执行 立即执行 延迟执行 链式调用 不支持(返回 void
)支持(可继续链式调用其他 LINQ 方法)
4. 常见误区
误区 1:认为 Select
不能修改原元素
- 实际上可以在
Select
中修改原元素,但通常不建议这样做(违背函数式编程原则)。 - 正确姿势:如果需要保留原集合,应克隆对象后修改:
var newList = list.Select(item => {var clone = item.Clone();clone.ColorIndex = 1;return clone;
}).ToList(); // 原集合不变,新集合包含修改后的克隆对象
误区 2:过度使用 ForEach
ForEach
本质是封装的foreach
循环,适合简单副作用操作。- 若需要过滤、聚合或与其他 LINQ 方法链式调用,应优先用
Select
。
5. 建议用法
- 用
ForEach
当:需要直接修改原集合元素,且无需生成新集合。 - 用
Select
当:- 需要生成新集合(无论是否修改原元素)。
- 需要与其他 LINQ 方法(如
Where
、Aggregate
)组合使用。
例如,筛选并修改元素:
var filteredPolylines = list.OfType<Polyline>() // 筛选Polyline类型(替代Where+类型检查).Select(polyline => {var clone = (Polyline)polyline.Clone(); // 克隆对象避免修改原集合clone.ColorIndex = 1; // 修改克隆对象的颜色return clone; // 返回修改后的新对象}).ToList();
var filteredAndModified = list.Where(item => item.IsActive).Select(item => {item.ColorIndex = 1;return item;}).ToList();
总结
ForEach
是命令式的副作用操作,适合直接修改原集合。Select
是声明式的映射操作,适合生成新集合或与其他 LINQ 操作组合。- 避免在
Select
中修改原元素,除非你明确需要这样做。