使用LINQ更改列表中对象的特性

本文关键字:对象 列表 LINQ 使用 | 更新日期: 2023-09-27 18:01:08

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

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();

使用LINQ更改列表中对象的特性

如果您的解决方案必须完全是Linq,则可以执行

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

然而,这并不是实现这一点的理想方式(@Jacob的答案更好(。查看Eric Lippert的博客文章。对我来说最重要的线路是

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

https://ericlippert.com/2009/05/18/foreach-vs-foreach/

请注意,之所以调用ToList(),是因为List<T>提供了ForEach()方法,而Linq通常不提供这样的扩展方法,原因是Eric Lippert在博客中引用了这一点。

更新

您的代码既更新原始列表中的实体(对于某些条件,将IsJoint更改为true(,又返回对已更新对象的引用。如果这是您想要的,那么代码就会起作用。然而,Linq在设计时考虑到了一种功能范式。在Linq表达式的上下文中引入副作用违反了扩展方法背后的函数编程原则。

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

假设我想为特定对象将Property Selected的值更改为true,那么我可以像这样做

Beams.Where(x => x.Width > 40).FirstorDefault(z=>z.Selected = true)

要实现功能纯,linq不会更改它正在处理的数据。这意味着你必须这样做。选择(x=>new Beam(x({IsJoist=true}(。然后,您将用结果替换原始列表。

我发现的最好的方法是new备份对象的副本,并在select中进行修改。如果有一个像js一样的传播就太好了。

一些未经测试的代码应该传达这个想法:


public class Cat {
   public string Name;
   public bool IsFerrel;
}
List<Cat> cats = new{
   new{Name="Tame"},
   new{Name="Wild"}
};
return cats.Select(c => new Cat{
  Name = c.Name,
  IsFerrel = c.Name.Contains("Wild")
};

从本质上讲,这采用了一种不改变对象的功能方法。

您可以尝试更改列表中所有项的属性(不带任何条件(。

Beams.All(b => b.IsJoist = true);