20

我有以下查询:

drivers.Select(d => { d.id = 0; d.updated = DateTime.Now; return d; }).ToList();

drivers 是一个包含不同 id 和更新值的列表,因此我正在更改 Select 中的值,但这是正确的方法。我已经知道我不会将驱动程序重新分配给驱动程序,因为 Resharper 抱怨它,所以我想如果是这样会更好:

drivers = drivers.Select(d => { d.id = 0; d.updated = DateTime.Now; return d; }).ToList();

但这仍然是某人应该为驱动程序列表中的每个元素分配新值的方式吗?

4

3 回答 3

37

虽然这看起来很无辜,尤其是结合ToList立即执行代码的调用,但我绝对不会修改任何作为查询的一部分:这个技巧非常不寻常,它会绊倒你的程序的读者,甚至是有经验的读者,特别是如果他们以前从未见过这个。

foreach循环没有任何问题——您可以使用 LINQ 执行此操作并不意味着您应该这样做。

于 2013-05-16T18:16:19.590 回答
33

永远不要这样做。一个查询应该是一个查询;它应该是非破坏性地询问数据源的问题。如果要引起副作用,请使用foreach循环;这就是它的用途。为工作使用正确的工具。

于 2013-05-16T18:26:56.833 回答
9

好的,我会自己回答。

Xaisoft,Linq查询,无论是 lambda 表达式还是查询表达式,都不应该用于变异列表。因此你的Select

drivers = drivers.Select(d => { d.id = 0; d.updated = DateTime.Now; return d; }).ToList();

是坏风格。它令人困惑/不可读,不标准,并且违背Linq哲学。实现最终结果的另一种糟糕方式是:

drivers.Any(d => { d.id = 0; d.updated = DateTime.Now; return false; });

But that's not to say ForEach on List<T> is inappropriate. It finds uses in cases like yours, but do not mix mutation with Linq query, thats all. I prefer to write something like:

drivers.ForEach(d => d.updated = DateTime.Now);

Its elegant and understandable. Since it doesn't deal with Linq, its not confusing too. I don't like that syntax for multiple statements (as in your case) inside the lambda. It's a little less readable and harder to debug when things get complex. In your case I prefer a straight foreach loop.

foreach (var d in drivers)
{ 
    d.id = 0; 
    d.updated = DateTime.Now; 
}

Personally I like ForEach on IEnumerable<T> as a terminating call to Linq expression (ie, if the assignment is not meant to be a query but an execution).

于 2013-05-16T18:50:00.780 回答