Pie*_*rre 12 c# linq paradigms list side-effects
我试图进一步了解副作用以及如何控制和应用它们.
在下面的航班列表中,我想设置满足条件的每个航班的属性:
IEnumerable<FlightResults> fResults = getResultsFromProvider();
//Set all non-stop flights description
fResults.Where(flight => flight.NonStop)
.Select(flight => flight.Description = "Fly Direct!");
Run Code Online (Sandbox Code Playgroud)
在这个表达式中,我对我的列表有副作用.从我有限的知识,我知道前."LINQ仅用于查询 "和"列表中只有少数操作,分配或设置值不是其中之一"和"列表应该是不可变的".
Fem*_*ref 13
您有两种方法可以实现LINQ方式:
显式foreach
循环
foreach(Flight f in fResults.Where(flight => flight.NonStop))
f.Description = "Fly Direct!";
Run Code Online (Sandbox Code Playgroud)与ForEach
操作员,为副作用:
fResults.Where(flight => flight.NonStop)
.ForEach(flight => flight.Description = "Fly Direct!");
Run Code Online (Sandbox Code Playgroud)第一种方式对于这么简单的任务来说非常沉重,第二种方式只能用于非常短的物体.
现在,您可能会问自己为什么ForEach
LINQ堆栈中没有运算符.这很简单 - LINQ应该是一种表达查询操作的功能方式,这尤其意味着没有任何操作符应该有副作用.设计团队决定不在ForEach
堆栈中添加操作符,因为唯一的用法是它的副作用.
ForEach
运营商的通常实现如下:
public static class EnumerableExtension
{
public static void ForEach<T> (this IEnumerable<T> source, Action<T> action)
{
if(source == null)
throw new ArgumentNullException("source");
foreach(T obj in source)
action(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法的一个问题是它根本不起作用.该查询是惰性的,这意味着它不会执行Select中的代码,直到您实际从查询中读取内容,而您永远不会这样做.
您可以通过.ToList()
在查询结尾添加来解决此问题,但代码仍然使用副作用并丢弃实际结果.您应该使用结果来执行更新:
//Set all non-stop flights description
foreach (var flight in fResults.Where(flight => flight.NonStop)) {
flight.Description = "Fly Direct!";
}
Run Code Online (Sandbox Code Playgroud)
您的LINQ代码不会"直接"违反您提到的指南,因为您没有修改列表本身; 你只是修改列表内容的一些属性.
但是,驱动这些指导原则的主要反对意见仍然存在:您不应该使用LINQ修改数据(同样,您也在滥用Select
执行副作用).
不修改任何数据可以很容易地证明是合理的.请考虑以下代码段:
fResults.Where(flight => flight.NonStop)
Run Code Online (Sandbox Code Playgroud)
你知道这在哪里修改航班属性吗?许多维护程序员也不会,因为他们会在以后的Where
代码中停止阅读- 因为这是一个查询,所以后面的代码 显然没有副作用,对吗?
[Nitpick:当然,看到一个不保留返回值的查询是一个死的赠品,查询确实有副作用或代码应该被删除; 无论如何,"有些事情是错的".但是,当只有两行代码而不是页面上的页面时,更容易说出来.
作为一个正确的解决方案,我建议这样做:
foreach (var x in fResults.Where(flight => flight.NonStop))
{
x.Description = "Fly Direct!";
}
Run Code Online (Sandbox Code Playgroud)
写入和读取都很容易.