Jak zaktualizować obiekt w List <> w C #

82

Mam kilka List<>niestandardowych obiektów.

Muszę znaleźć obiekt na tej liście według jakiejś unikalnej właściwości i zaktualizować inną właściwość tego obiektu.

Jak to zrobić najszybciej?

Burjua
źródło

Odpowiedzi:

109

Używając Linq, aby znaleźć obiekt, który możesz zrobić:

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

Ale w tym przypadku możesz zechcieć zapisać listę w słowniku i zamiast tego użyć tego:

// ... 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
źródło
4
Dzięki CKoenig, czy to otrzyma odniesienie do objlub wartość (kopia)? innymi słowy, czy obiekt na liście zostanie zmieniony?
Burjua,
4
Myślę, że to nie będzie działać, jeśli obiekt jest typu struct, sprawiają, że klasę :)
Sara S.
27
Ponieważ masz listę obiektów niestandardowych (zakładając, że jest to klasa, a nie struktura), masz do czynienia z typem referencyjnym, będzie to odniesienie do tego obiektu i modyfikacja go „utrwali” - zmodyfikuje obiekt w kolekcja.
Matt Roberts,
1
to znajdzie odniesienie (więc tak, będzie to obiekt na liście) i powinno również działać ze strukturami - ale szczerze mówiąc, musiałem spróbować się upewnić - ale nie widzę, dlaczego nie ATM
Carsten
2
@CKoenig - To nie działałoby ze strukturami, dodano odpowiedź poniżej z przykładem kodu do zademonstrowania
Matt Roberts
30

Wystarczy dodać do odpowiedzi CKoeniga. Jego odpowiedź będzie działać, o ile klasa, z którą masz do czynienia, jest typem referencyjnym (jak klasa). Jeśli obiekt niestandardowy był strukturą, jest to typ wartości, a wyniki działania .FirstOrDefaultda ci lokalną kopię tego, co oznacza, że ​​nie zostanie zachowany z powrotem w kolekcji, jak pokazano w tym przykładzie:

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

Kod testowy:

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

Wynik to 10,1145

Zmień strukturę na klasę, a wynik to 10,12,145

HTH

Matt Roberts
źródło
ok dzięki. przypuszczam, że zamiast lokalnej kopii otrzymasz odniesienie do struktury.
Carsten,
18

lub bez linq

foreach(MyObject obj in myList)
{
   if(obj.prop == someValue)
   {
     obj.otherProp = newValue;
     break;
   }
}
Erix
źródło
1
Tak, to oczywista odpowiedź, ale nie chcę używać wszystkich, myślę, że jest to najwolniejszy sposób
Burjua
Czy ktoś może wypowiedzieć się na temat tego, czy powyższa metoda LINQ jest rzeczywiście bardziej wydajna niż ta?
pseudocoder,
6
Jeśli jest jakaś różnica, wersja linq jest prawdopodobnie wolniejsza.
Erix,
7
@Burjua Uważa się, że możemy zobaczyć rzeczywistą pętlę zachodzącą w bloku foreach, podczas gdy w Linq / Lambda nie, więc zakładamy, że foreach jest wolniejsze i staramy się tego uniknąć. Rzeczywistość jest zawsze / dla /, podczas gdy pętle są znacznie szybsze.
harsimranb
Cóż, wolniej / szybciej, nie wiem które ... ale w moim przypadku i tak miałem do czynienia z małymi płytami i nie chciałem zbytnio o tym myśleć. To zadziałało! Miły akcent z przerwą;
Anthony Griggs
9

Można też spróbować.

 _lstProductDetail.Where(S => S.ProductID == "")
        .Select(S => { S.ProductPcs = "Update Value" ; return S; }).ToList();
BJ Patel
źródło
3
Działa to z listą lub tablicą, ale nie z IEnumerable
Lord Darth Vader
6
var itemIndex = listObject.FindIndex(x => x == SomeSpecialCondition());
var item = listObject.ElementAt(itemIndex);
item.SomePropYouWantToChange = "yourNewValue";
codeMonkey
źródło
2
Nie ma potrzeby usuwania obiektu z listy i ponownego wstawiania go (bardzo nieefektywne). Obiekty są typami referencyjnymi. Gdy masz już odniesienie do obiektu, po prostu zaktualizuj obiekt, ponieważ jest taki sam jak obiekt na liście.
humbads
1
Jeszcze jedna sugestia. FindIndex może zwrócić -1, w takim przypadku ElementAt zgłosi wyjątek.
humbads
4

Możesz zrobić coś takiego:

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
źródło
0

To było dziś nowe odkrycie - po zapoznaniu się z lekcją referencyjną dotyczącą klasy / struktury!

Możesz użyć Linq i „Single”, jeśli wiesz, że element zostanie znaleziony, ponieważ Single zwraca zmienną ...

myList.Single(x => x.MyProperty == myValue).OtherProperty = newValue;
Dave
źródło