2014-04-30 48 views
1

我有Beam对象的列表。当使用LINQ的Width属性大于40时,如何更改光束的IsJoist属性?使用LINQ更改列表中对象的属性

class Beam 
{ 
    public double Width { get; set; } 
    public bool IsJoist { get; set; } 
} 

var bm1 = new Beam { Width = 40 }; 
var bm2 = new Beam { Width = 50 }; 
var bm3 = new Beam { Width = 30 }; 
var bm4 = new Beam { Width = 60 }; 

var Beams = new List<Beam> { bm1, bm2, bm3, bm4 }; 

这是我所做的,但我只得到一个列表。我希望新列表与原始列表相同,只是某些梁的IsJoist属性将设置为true。

var result = Beams 
    .Where(x => x.Width > 40) 
    .Select(x => x.IsJoist = true) 
    .ToList(); 

我能够实现这一点如下。是否可以,因为LINQ是用于查询的?

var result = Beams 
    .Where(x => x.Width > 40) 
    .Select(x => 
    { 
     x.IsJoist = true; 
     return x; 
    }) 
    .ToList(); 
+1

你不能。这些方法**的全部要点在于它们是功能性的。那是......他们有**没有副作用**。除非你在'List '类型中使用“破坏”方法'ForEach'。 –

+0

@SimonWhitehead我实际上找到了答案,它正在工作,但我不知道这是否是好习惯? – Vahid

+3

永远不会永远不会使用选择行为像更新,这是一个可怕的编程习惯。使用LINQ *提问*,而不是*进行更改*。如果你想改变,使用'foreach'循环。 –

回答

8

如果您的解决方案必须是完全的LINQ,你可以做

Beams.Where(x => x.Width > 40).ToList().ForEach(b => b.IsJoist = true); 

然而,这并不是实现这个(@雅各布的回答是更好的一个)的理想方式。查看Eric Lippert关于该主题的博客文章。对我来说最重要的线路是

第一个原因是这样做违反了所有其他序列运算符所基于的函数式编程原则。显然,调用这种方法的唯一目的是引起副作用。表达式的目的是计算一个值,而不是引起副作用。声明的目的是引起副作用。

http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx

注意ToList()叫,因为List<T>提供ForEach()方法,而LINQ的一般不提供的原因埃里克利珀援引在博客中这样的扩展方法。

UPDATE

您的代码在原始列表中两个更新实体(改变IsJoist到真正某些条件),并返回引用已更新的对象。如果这是你的意图,代码的功能。但是,Linq的设计思路是功能范例。在Linq表达式的上下文中引入副作用违反了扩展方法背后的函数编程原则。

+0

谢谢。你也可以看看我的实现吗? – Vahid

+1

看看我的更新。 –

+1

先生Lippert的报价+1。我不记得谁说过这样的话,所以我在我的评论中无法链接到它。 –

4
foreach(Beam beam in Beams.Where(x => x.Width > 40)) 
{ 
    beam.IsJoist = true; 
} 
+0

我希望它完全在LINQ中。 – Vahid

+3

@Vahid LINQ仅用于查询而不用于更改值。 –

+0

问题是,“梁”被声明为列表中的新变量。是的,价值正在改变,但没有在列表中。 – Ewald

1

为了保持功能纯正,您的linq不会改变它正在处理的数据。这意味着你必须选择(x => new Beam(x){IsJoist = true})。然后你会用结果替换原来的列表。

1

假设我想更改选定为true特定对象属性的值,那么我可以这样做

Beams.Where(x => x.Width > 40).FirstorDefault(z=>z.Selected = true) 
相关问题