Cómo actualizar un objeto en una lista <> en C #

81

Tengo List<>varios objetos personalizados.

Necesito encontrar un objeto en esta lista por alguna propiedad que sea única y actualizar otra propiedad de este objeto.

¿Cuál es la forma más rápida de hacerlo?

Burjua
fuente

Respuestas:

108

Usando Linq para encontrar el objeto puede hacer:

var obj = myList.FirstOrDefault(x => x.MyProperty == myValue);
if (obj != null) obj.OtherProperty = newValue;

But in this case you might want to save the List into a Dictionary and use this instead:

// ... define after getting the List/Enumerable/whatever
var dict = myList.ToDictionary(x => x.MyProperty);
// ... somewhere in code
MyObject found;
if (dict.TryGetValue(myValue, out found)) found.OtherProperty = newValue;
Carsten
fuente
4
Thanks CKoenig, will this get a reference to obj or value(copy)? in other words, will be the object inside the list changed?
Burjua
4
I think that this would not work if the object is of type struct, make it a class:)
Sara S.
27
Because you have a list of custom objects (assuming its a class and not a struct), you're dealing with a reference type, it will be a reference to that object and modifying it will "persist" - it will modify the object in the collection.
Matt Roberts
1
this will find the reference (so yes it will be the object in the list) and it should work with structs too - but to be honest I had to try to be sure there - but I don't see why not ATM
Carsten
2
@CKoenig - It wouldn't work with structs, added a response below with code example to demonstrate
Matt Roberts
29

Just to add to CKoenig's response. His answer will work as long as the class you're dealing with is a reference type (like a class). If the custom object were a struct, this is a value type, and the results of .FirstOrDefault will give you a local copy of that, which will mean it won't persist back to the collection, as this example shows:

struct MyStruct
{
    public int TheValue { get; set; }
}

Test code:

List<MyStruct> coll = new List<MyStruct> {
                                            new MyStruct {TheValue = 10},
                                            new MyStruct {TheValue = 1},
                                            new MyStruct {TheValue = 145},
                                            };
var found = coll.FirstOrDefault(c => c.TheValue == 1);
found.TheValue = 12;

foreach (var myStruct in coll)
{
    Console.WriteLine(myStruct.TheValue);
}
Console.ReadLine();

The output is 10,1,145

Change the struct to a class and the output is 10,12,145

HTH

Matt Roberts
fuente
ok - thanks. my guess woult have been that you get a reference to the struct as well instead of a local copy.
Carsten
18

or without linq

foreach(MyObject obj in myList)
{
   if(obj.prop == someValue)
   {
     obj.otherProp = newValue;
     break;
   }
}
Erix
fuente
1
Yes, this is obvious answer, but I don't want to use foreach, I guess this is the slowest way to do it
Burjua
Can anyone comment on whether the LINQ method above is actually more efficient than this one?
pseudocoder
6
If there is any difference, the linq version is probably slower.
Erix
7
@Burjua The perception is that we can see the actual loop happening in the foreach block, whereas in Linq/Lambda we don't, so we assume foreach is slower and try to avoid it. Reality is foreach/for/while loops are much faster.
harsimranb
Well slower/ faster I don't know which... but in my case I was dealing with small records anyway and didn't want to think about it to much. This worked! Nice touch with the break;
Anthony Griggs
9

Can also try.

 _lstProductDetail.Where(S => S.ProductID == "")
        .Select(S => { S.ProductPcs = "Update Value" ; return S; }).ToList();
BJ Patel
fuente
3
This works with a list or an array, but not a IEnumerable
Lord Darth Vader
6
var itemIndex = listObject.FindIndex(x => x == SomeSpecialCondition());
var item = listObject.ElementAt(itemIndex);
item.SomePropYouWantToChange = "yourNewValue";
codeMonkey
fuente
1
There's no need to remove the object from the list and re-insert it (very inefficient). Objects are reference types. Once you have a reference to the object, just update the object as it is one and the same as the object in the list.
humbads
One more suggestion. FindIndex may return -1, in which case ElementAt will throw an exception.
humbads
4

You can do somthing like :

if (product != null) {
    var products = Repository.Products;
    var indexOf = products.IndexOf(products.Find(p => p.Id == product.Id));
    Repository.Products[indexOf] = product;
    // or 
    Repository.Products[indexOf].prop = product.prop;
}
Halimi
fuente
0

This was a new discovery today - after having learned the class/struct reference lesson!

You can use Linq and "Single" if you know the item will be found, because Single returns a variable...

myList.Single(x => x.MyProperty == myValue).OtherProperty = newValue;
Dave
fuente