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

时间:2009-04-30 16:23:24

标签: c# linq

使用LINQ,如果我想执行一些查询并从查询中返回对象,但只更改该对象中的某些属性,如何在不创建新对象的情况下执行此操作并手动设置每个属性?这可能吗?

示例:

var list = from something in someList
           select x // but change one property

11 个答案:

答案 0 :(得分:337)

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

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

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

答案 1 :(得分:54)

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

someList.All(x => { x.SomeProp = "foo"; return true; })

答案 2 :(得分:29)

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

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

答案 3 :(得分:19)

不应该有任何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;
}

答案 4 :(得分:9)

标准查询运算符无法实现 - 它是语言集成查询,而不是语言集成更新。但您可以在扩展方法中隐藏更新。

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

答案 5 :(得分:2)

如果您要更新带有Where子句的项目,使用.Where(...)会截断您的结果:

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

您可以对列表中的特定项目进行更新,如下所示:

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

即使您不做任何更改,也始终返回项目。这样它就会保留在列表中。

答案 6 :(得分:0)

var item = (from something in someList
       select x).firstordefault();

获得item,然后您可以item.prop1=5;更改特定属性。

或者您是否希望从数据库中获取项目列表并将其返回列表中每个项目的属性prop1更改为指定值? 如果是这样你可以这样做(我在VB中这样做,因为我知道它更好):

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

list将包含随更改返回的所有项目)

答案 7 :(得分:0)

由于我没有在这里找到我认为最佳解决方案的答案,所以我的方式:

使用“选择”来修改数据是可能的,但只需要一个技巧。无论如何,“选择”不是为此而做的。它只是在与“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 ......

答案 8 :(得分:0)

我们经常遇到这种情况,我们希望在列表中包括索引值以及第一个和最后一个指示符,而无需创建新对象。这样一来,您无需修改​​现有类就可以知道项目在列表,枚举等中的位置,而不必知道您位于列表的第一项还是最后一项。

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 {}

答案 9 :(得分:0)

答案 10 :(得分:-3)

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