通过LINQ将函数应用于集合中的所有元素。
问题的出现原因:在使用LINQ的过程中,有时候需要对集合中的所有元素应用同一个函数。然而,直接使用LINQ的方法并不能满足需求,需要找到一种更有效的方法。
解决方法:可以考虑使用并行编程来提高效率,特别是当不关心元素的顺序,更关心每个元素都能完成某些操作时。可以使用AsParallel()
方法将集合转换为并行集合,然后使用ForAll()
方法将函数应用于所有元素。
例如,可以这样使用:
var numbers = new[] { 1, 2, 3, 4, 5 }; numbers.AsParallel().ForAll(Console.WriteLine);
需要注意的是,使用AsParallel().ForAll()
可能导致结果不可预测。例如,当点击一个按钮时执行以下代码:myEnumerable.AsParallel().ForAll(i as string => otherDictionary.Add(i, 0))
,会将null作为键添加到otherDictionary
中。为了解决这个问题,可以改用foreach循环来遍历集合。
然而,并不是AsParallel().ForAll()
方法本身的问题,而是在多个线程之间使用共享状态,以及将"i as string"转换为null键的可能原因。如果能提供更完整的代码样例,可以得到关于如何改进的反馈意见。
使用LINQ的惯用方式是处理集合并返回一个按照你想要的方式映射的新集合。例如,要为每个元素添加一个常量,你可以使用以下代码:
var newNumbers = oldNumbers.Select(i => i + 8);
以函数式的方式进行操作而不是改变现有集合的状态,经常有助于将不同的操作分离开来,这样既更易于阅读,也更容易让编译器进行推理。
如果你需要对集合的每个元素应用一个与集合内容无关的副作用的操作,那么LINQ并不是最适合的工具,尽管你可以使用`Select`来模拟(或者编写自己的`IEnumerable`扩展方法,许多人都这样做)。在这种情况下,最好使用`foreach`循环。
更不用说在迭代过程中改变集合是危险的,或者在某些语言中是不可能的。
在C#中,改变集合元素是可以的,但是添加或删除元素可能会失败或产生意外结果。
使用`Select`方法只对某些类型(如`int`)真正有帮助。如果你想将列表中的对象属性设置为特定值,使用`.ForEach()`更简单且可扩展吗?
如果你已经知道新值,那么通常(按照LINQ的精神),你会倾向于创建一个包含适当值的新列表,而不是修改旧列表。当然,如果你确实有一个列表,并且真的想改变那个特定的列表(也许它与某个数据绑定),那么使用`.ForEach()`也可以。
如果你不在之后迭代`Select`的结果,那么LINQ的延迟执行可能会成为一个问题。
`ForEach`不会改变集合,它通常用于编辑集合中的元素。个人而言,我会将编辑后的集合作为结果返回,但因人而异。
`Select`方法也适用于你的用例(将对象的属性设置为特定值)。示例:
myItems.Select(item => { item.myProperty = someValue(); return item; } );
问题的出现原因是有时候需要对集合的每个元素应用一个操作,而LINQ中的`Select`方法只是返回一个新的映射集合,并没有直接修改原始集合的能力。解决方法是根据具体情况选择使用`Select`方法或`ForEach`方法,或者在需要修改原始集合的情况下使用`foreach`循环。
在LINQ中,有时候我们需要对一个集合中的所有元素应用一个函数。虽然LINQ提供了很多操作符,但是没有直接提供这样的功能。因此,一些开发者会自己添加一个ForEach方法来实现这个功能。
为了演示这个问题,我们可以看看在MoreLINQ库中的ForEach方法的实现。该方法定义在IEnumerable
public static void ForEach
{
source.ThrowIfNull("source");
action.ThrowIfNull("action");
foreach (T element in source)
{
action(element);
}
}
这个方法的实现比较简单,首先会对源集合和操作参数进行空引用检查,然后使用foreach循环对集合中的每个元素应用操作。
使用这个方法,我们可以在LINQ查询中写出类似下面的代码:
people.Where(person => person.Age < 21)
.ForEach(person => person.EjectFromBar());
这段代码的意思是,从people集合中筛选出年龄小于21岁的人,并对每个人调用EjectFromBar方法。
有些开发者认为使用ForEach方法可以提高代码的可读性,但也有一些开发者认为直接使用foreach循环更加清晰。使用ForEach方法可以将数据获取和操作分离,从而更好地理清算法的结构。
然而,也有开发者质疑使用ForEach方法是否符合函数式编程的目标。在函数式编程中,尽量避免使用带有副作用的方法,而ForEach方法显然违背了这个原则。因此,有人认为使用ForEach方法既不是纯粹的函数式编程,也不是传统的foreach循环,而是两者之间的折中。
此外,还有一些开发者提出了使用Select方法来实现类似功能的建议。Select方法是LINQ中的一个投影操作符,可以对集合中的每个元素进行映射。通过在Select方法中使用一个lambda表达式,我们可以在不修改原始元素的情况下对其进行操作。
使用ForEach方法可以在LINQ查询中对集合中的每个元素应用一个操作,但是这种做法存在一些争议。开发者们对于使用ForEach方法的好处和适用场景有不同的看法,因此在实际开发中需要根据具体情况来决定是否使用该方法。另外,也有其他的方法可以实现类似的功能,例如使用Select方法来对元素进行操作。