2014-04-30 91 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) 
相關問題