选择一个对象并更改一些属性,而不创建一个新对象

我想改变一个LINQ查询结果对象的一些属性,而不需要创建一个新的对象和手动设置每个属性。这可能吗?

例子:

var list = from something in someList
select x // but change one property
292065 次浏览

我不确定查询语法是什么。下面是扩展的LINQ表达式示例。

var query = someList.Select(x => { x.SomeProp = "foo"; return x; })

它所做的是使用匿名方法vs和表达式。这允许您在一个lambda中使用多个语句。因此,您可以将设置属性和返回对象这两个操作结合到这个稍微简洁的方法中。

这对于标准查询操作符是不可能的——它是语言集成查询,而不是语言集成更新。但是您可以将更新隐藏在扩展方法中。

public static class UpdateExtension
{
public static IEnumerable<Car> ChangeColorTo(
this IEnumerable<Car> cars, Color color)
{
foreach (Car car in cars)
{
car.Color = color;
yield return car;
}
}
}

现在您可以像下面这样使用它。

cars.Where(car => car.Color == Color.Blue).ChangeColorTo(Color.Red);

不应该有任何LINQ魔法阻止你这样做。不要使用投影,那会返回一个匿名类型。

User u = UserCollection.FirstOrDefault(u => u.Id == 1);
u.FirstName = "Bob"

这将修改真实对象,以及:

foreach (User u in UserCollection.Where(u => u.Id > 10)
{
u.Property = SomeValue;
}
var item = (from something in someList
select x).firstordefault();

会得到item,然后你可以用item.prop1=5;来改变特定的属性。

或者你想从db中获得一个项目列表,并让它将返回列表中每个项目的属性prop1更改为指定的值? 如果是这样,你可以这样做(我在VB中这样做,因为我知道它更好):

dim list = from something in someList select x
for each item in list
item.prop1=5
next

(list将包含您的更改返回的所有项)

如果你只是想更新所有元素的属性,那么

someList.All(x => { x.SomeProp = "foo"; return true; })
User u = UserCollection.Single(u => u.Id == 1);
u.FirstName = "Bob"

我更喜欢这个。它可以与其他linq命令组合使用。

from item in list
let xyz = item.PropertyToChange = calcValue()
select item

由于我在这里没有找到我认为最好的解决方案的答案,下面是我的方法:

使用“选择”来修改数据是可能的,但只是一个技巧。总之,"选择"不是为这个设计的。它只在与“ToList”一起使用时执行修改,因为Linq在需要数据之前不会执行。 无论如何,最好的解决方案是使用“foreach”。在下面的代码中,你可以看到:

    class Person
{
public int Age;
}


class Program
{
private static void Main(string[] args)
{
var persons = new List<Person>(new[] {new Person {Age = 20}, new Person {Age = 22}});
PrintPersons(persons);


//this doesn't work:
persons.Select(p =>
{
p.Age++;
return p;
});
PrintPersons(persons);


//with "ToList" it works
persons.Select(p =>
{
p.Age++;
return p;
}).ToList();
PrintPersons(persons);


//This is the best solution
persons.ForEach(p =>
{
p.Age++;
});
PrintPersons(persons);
Console.ReadLine();
}


private static void PrintPersons(List<Person> persons)
{
Console.WriteLine("================");
foreach (var person in persons)
{
Console.WriteLine("Age: {0}", person.Age);
;
}
}
}

在"foreach"之前,你也可以做一个linq选择…

如果你想用Where子句更新项,使用.Where(…)将截断你的结果:

list = list.Where(n => n.Id == ID).Select(n => { n.Property = ""; return n; }).ToList();

你可以像这样更新列表中的特定项目:

list = list.Select(n => { if (n.Id == ID) { n.Property = ""; } return n; }).ToList();

总是返回项目,即使你不做任何改变。这样它将被保存在列表中。

在不创建新对象的情况下,我们经常会遇到这种情况,即在列表中包含索引值和第一个和最后一个指标。这允许您知道项在列表、枚举等中的位置,而不必修改现有的类,然后知道您是在列表中的第一个项还是最后一个项。

foreach (Item item in this.Items
.Select((x, i) => {
x.ListIndex = i;
x.IsFirst = i == 0;
x.IsLast = i == this.Items.Count-1;
return x;
}))

你可以简单地扩展任何类,使用:

public abstract class IteratorExtender {
public int ListIndex { get; set; }
public bool IsFirst { get; set; }
public bool IsLast { get; set; }
}


public class Item : IteratorExtender {}

我遇到了确切的要求(OP的问题),我没有看到在任何地方用表达来回答。

假设x类型为MyType,您可以调用一个返回MyType的方法,该方法接受x。在这个方法中,你可以做所有你想做的修改。代码看起来像这样。

var list = from something in someList
select GetModifiedObject(x); // but change one property


private MyType GetModifiedObject(MyType x)
{
x.Property1 = "Changed Value";
return x;
}
这是最简单的解决方案: list.Where(t => t.Id == 1).ToList().ForEach(t => t.Property = "something"); < / p >

尝试和工作,引用自这里: https://visualstudiomagazine.com/articles/2019/07/01/updating-linq.aspx < / p >

使用ForEach

var list = from something in someList;
list.ForEach(x => x.Property = value);