270

I want to change some properties of a LINQ query result object without creating a new object and manually setting every property. Is this possible?

Example:

var list = from something in someList
           select x // but change one property
plr108
  • 1,201
  • 11
  • 16
Rob Volk
  • 5,204
  • 5
  • 25
  • 19
  • 1
    sorry about that! ihere's the correct address: https://robvolk.com/linq-select-an-object-but-change-some-properties-without-creating-a-new-object-af4072738e33 – Rob Volk Feb 10 '17 at 15:57
  • 1
    See also: https://stackoverflow.com/questions/47836019/linq-set-a-property-while-doing-a-projection?noredirect=1#47836189 – Revious Dec 15 '17 at 16:27
  • 2
    While this can be done, as the answers show, please note that this violates the nature of LINQ. LINQ methods are not supposed to cause side effects so doing this is not in keeping with the principle of least surprise. True to LINQ, you'd get the objects and then modify them. – Gert Arnold Mar 06 '22 at 21:38

14 Answers14

463

I'm not sure what the query syntax is. But here is the expanded LINQ expression example.

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

What this does is use an anonymous method vs and expression. This allows you to use several statements in one lambda. So you can combine the two operations of setting the property and returning the object into this somewhat succinct method.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Thanks, your solution works nicely. How would you write it using query syntax? – Rob Volk May 11 '09 at 15:43
  • 6
    @Rob, Not easily. The syntax to get that working is ... unreadable at best. var query = from it in list select ((Func)(() => { it.x = 42; return it; }))(); – JaredPar May 11 '09 at 16:06
  • 50
    I am getting "A lambda expression with a statement body cannot be converted to an expression tree" error. Its not for LINQ to SQL, any advice? – surya Feb 15 '12 at 16:22
  • 2
    @spiderdevil +1 for you - don't you just hate the disparity? This isn't the first time I have run into a situation where code only works for Linq to Object and not Linq to SQL/EF. This might be a solution [here](http://stackoverflow.com/a/466266/603807), but I haven't tried to use it yet because I don't have the time. – dyslexicanaboko Feb 14 '13 at 21:04
  • Could someone please explain how it works? Is `return x` there to return the object itself? – Celdor Feb 11 '15 at 12:22
  • 14
    @surya That is exactly the message I got when trying it with Linq to SQL. Adding a `ToList()` before that seems to do the trick. Not sure why you get that though. If it is Entity Framework, it does not work with that either. – Thomas Glaser May 20 '15 at 13:36
  • you can use .toList() to retrieve a new instance of list with the modified property. List list = someList.Select(x => { x.SomeProp = "foo"; return x; }).toList – Alessio Campanelli Oct 27 '15 at 16:16
  • 6
    @surya when you call ToList() you're actually bringing the data back into memory. So its not actually Linq to SQL anymore then. – Oak Mar 24 '16 at 07:33
  • 8
    According to Eric Lippert this solution is "... inefficient, confusing, unmaintainable, unnecessary, wasteful, depends on implementation details of the query operators, does not generalize to non-LINQ-to-objects scenarios, and an abuse of an operator intended to answer a question, not execute a side effect.". See his comments to [this anwer](https://stackoverflow.com/a/47397985/1846281) – Luca Cremonesi Nov 20 '17 at 20:58
  • Why `var query = someList.Select(x => x.Login)` is giving me a null reference exception? `someList` is a list of objects which contains `Login` property. All objects have Login value assigned and none object is null – XardasLord Oct 17 '18 at 12:59
70

If you just want to update the property on all elements then

someList.All(x => { x.SomeProp = "foo"; return true; })
Mahmoud Gamal
  • 78,257
  • 17
  • 139
  • 164
Jon Spokes
  • 2,599
  • 2
  • 18
  • 21
  • 3
    In EF (Entity Framework): to replace a property on all objects of a IEnumerable, the accepted answer worked for me. Working code for me: var myList = _db.MyObjects.Where(o => o.MyProp == "bar").AsEnumerable().Select(x => { x.SomeProp = "foo"; return x; }); – firepol Jun 04 '13 at 13:38
37

I prefer this one. It can be combined with other linq commands.

from item in list
let xyz = item.PropertyToChange = calcValue()
select item
Jan Zahradník
  • 2,417
  • 2
  • 33
  • 44
33

There shouldn't be any LINQ magic keeping you from doing this. Don't use projection though that'll return an anonymous type.

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

That will modify the real object, as well as:

foreach (User u in UserCollection.Where(u => u.Id > 10)
{
    u.Property = SomeValue;
}
Joshua Belden
  • 10,273
  • 8
  • 40
  • 56
  • I like this, my question is in first example what if some u > 10 is not found in list? I added a null check and seems to work. Also LHS I named u to v. +1 though. Very concise. – One-One Apr 20 '12 at 11:25
14

If you want to update items with a Where clause, using a .Where(...) will truncate your results if you do:

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

You can do updates to specific item(s) in the list like so:

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

Always return item even if you don't make any changes. This way it will be kept in the list.

Pierre
  • 8,397
  • 4
  • 64
  • 80
12

It is not possible with the standard query operators - it is Language Integrated Query, not Language Integrated Update. But you could hide your update in extension methods.

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

Now you can use it as follows.

cars.Where(car => car.Color == Color.Blue).ChangeColorTo(Color.Red);
Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
  • 1
    It's not that you want to update the base collection. We want the result collection property updated. – Michael Brennt Sep 18 '14 at 13:01
  • 4
    Well LINQ replaces SQL which stands for Structured *Query* Language, but it still exposes the ability ability to `UPDATE`, `DELETE`, and `INSERT`. So I wouldn't argue that semantics is the thing preventing this function. – KyleMit Aug 28 '15 at 18:56
2

We often run into this where we want to include a the index value and first and last indicators in a list without creating a new object. This allows you to know the position of the item in your list, enumeration, etc. without having to modify the existing class and then knowing whether you're at the first item in the list or the last.

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

You can simply extend any class by using:

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

public class Item : IteratorExtender {}
1

Since I didn´t find the answer here which I consider the best solution, here my way:

Using "Select" to modify data is possible, but just with a trick. Anyway, "Select" is not made for that. It just executes the modification when used with "ToList", because Linq doesn´t execute before the data is being needed. Anyway, the best solution is using "foreach". In the following code, you can see:

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

Before "foreach", you can also make a linq selection...

Stefan R.
  • 438
  • 1
  • 5
  • 22
1

In 2020 I use the MoreLinq Pipe method. https://morelinq.github.io/2.3/ref/api/html/M_MoreLinq_MoreEnumerable_Pipe__1.htm

Victor Wilson
  • 1,720
  • 1
  • 11
  • 22
0

This is the very easiest solution: list.Where(t => t.Id == 1).ToList().ForEach(t => t.Property = "something");

Tried and worked, quoted from here: https://visualstudiomagazine.com/articles/2019/07/01/updating-linq.aspx

alexDuty
  • 72
  • 1
  • 8
0

Use ForEach

var list = from something in someList;
list.ForEach(x => x.Property = value);
RAM
  • 475
  • 1
  • 3
  • 14
0
var item = (from something in someList
       select x).firstordefault();

Would get the item, and then you could do item.prop1=5; to change the specific property.

Or are you wanting to get a list of items from the db and have it change the property prop1 on each item in that returned list to a specified value? If so you could do this (I'm doing it in VB because I know it better):

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

(list will contain all the items returned with your changes)

d219
  • 2,707
  • 5
  • 31
  • 36
Solmead
  • 4,158
  • 2
  • 26
  • 30
  • While this will work, I think the OP was asking how to write the LINQ statement without having to write a `for each` loop. – fujiiface Oct 08 '15 at 00:02
-1

I ran into the exact requirement (OP's question) and I don't see that being answered anywhere above using expressions.

Assuming x is of type MyType, you can call a method that returns MyType, which takes in x. Inside that method you can do all the modifications you want. The code will look something like this.

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

private MyType GetModifiedObject(MyType x)
{
   x.Property1 = "Changed Value";
   return x;
}
James Poulose
  • 3,569
  • 2
  • 34
  • 39
-3
User u = UserCollection.Single(u => u.Id == 1);
u.FirstName = "Bob"
kazem
  • 3,671
  • 1
  • 22
  • 21
  • 1
    No need to duplicate the [existing answers on this thread](http://stackoverflow.com/a/807848/1366033). If you have a comment about that answer, you can place it there. – KyleMit Aug 28 '15 at 19:00