So aktualisieren Sie ein Objekt in einer Liste <> in C #

81

Ich habe ein List<>benutzerdefiniertes Objekt.

Ich muss ein Objekt in dieser Liste anhand einer Eigenschaft finden, die eindeutig ist, und eine andere Eigenschaft dieses Objekts aktualisieren.

Was ist der schnellste Weg, dies zu tun?

Burjua
quelle

Antworten:

108

Verwenden Sie Linq, um das Objekt zu finden, das Sie tun können:

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

In diesem Fall möchten Sie die Liste möglicherweise in einem Wörterbuch speichern und stattdessen Folgendes verwenden:

// ... 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
quelle
4
Danke CKoenig, wird dies einen Verweis auf objoder einen Wert (Kopie) bekommen? Mit anderen Worten, wird das Objekt in der Liste geändert?
Burjua
4
Ich denke, dass dies nicht funktionieren würde, wenn das Objekt vom Typ struct ist, machen Sie es zu einer Klasse :)
Sara S.
27
Da Sie eine Liste mit benutzerdefinierten Objekten haben (vorausgesetzt, es handelt sich um eine Klasse und nicht um eine Struktur), handelt es sich um einen Referenztyp. Es handelt sich um eine Referenz auf dieses Objekt, und durch Ändern wird es "beibehalten" - das Objekt wird geändert die Sammlung.
Matt Roberts
1
Dies wird die Referenz finden (also ja, es wird das Objekt in der Liste sein) und es sollte auch mit Strukturen funktionieren - aber um ehrlich zu sein, musste ich versuchen, dort sicher zu sein - aber ich verstehe nicht, warum nicht ATM
Carsten
2
@CKoenig - Es würde nicht mit Strukturen funktionieren, fügte eine Antwort unten mit Codebeispiel hinzu, um zu demonstrieren
Matt Roberts
29

Nur um CKoenigs Antwort zu ergänzen. Seine Antwort funktioniert, solange die Klasse, mit der Sie sich befassen, ein Referenztyp ist (wie eine Klasse). Wenn das benutzerdefinierte Objekt eine Struktur wäre, ist dies ein Werttyp, und die Ergebnisse von .FirstOrDefaultgeben Ihnen eine lokale Kopie davon, was bedeutet, dass es nicht in der Auflistung verbleibt, wie dieses Beispiel zeigt:

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

Testcode:

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

Die Ausgabe ist 10,1,145

Ändern Sie die Struktur in eine Klasse und die Ausgabe ist 10,12,145

HTH

Matt Roberts
quelle
OK danke. Ich vermute, dass Sie anstelle einer lokalen Kopie auch einen Verweis auf die Struktur erhalten.
Carsten
18

oder ohne linq

foreach(MyObject obj in myList)
{
   if(obj.prop == someValue)
   {
     obj.otherProp = newValue;
     break;
   }
}
Erix
quelle
1
Ja, das ist eine offensichtliche Antwort, aber ich möchte foreach nicht verwenden. Ich denke, dies ist der langsamste Weg, dies zu tun
Burjua,
Kann jemand kommentieren, ob die obige LINQ-Methode tatsächlich effizienter ist als diese?
Pseudocoder
6
Wenn es einen Unterschied gibt, ist die Linq-Version wahrscheinlich langsamer.
Erix
7
@Burjua Die Wahrnehmung ist, dass wir die tatsächliche Schleife im foreach-Block sehen können, während dies in Linq / Lambda nicht der Fall ist. Daher gehen wir davon aus, dass foreach langsamer ist, und versuchen, dies zu vermeiden. Die Realität ist für jede / für / während Schleifen viel schneller sind.
Harsimranb
Nun, langsamer / schneller, ich weiß nicht welche ... aber in meinem Fall hatte ich es trotzdem mit kleinen Platten zu tun und wollte nicht zu viel darüber nachdenken. Das hat funktioniert! Nette Berührung mit der Pause;
Anthony Griggs
9

Kann es auch versuchen.

 _lstProductDetail.Where(S => S.ProductID == "")
        .Select(S => { S.ProductPcs = "Update Value" ; return S; }).ToList();
BJ Patel
quelle
3
Dies funktioniert mit einer Liste oder einem Array, aber nicht mit einem IEnumerable
Lord Darth Vader
6
var itemIndex = listObject.FindIndex(x => x == SomeSpecialCondition());
var item = listObject.ElementAt(itemIndex);
item.SomePropYouWantToChange = "yourNewValue";
codeMonkey
quelle
1
Es ist nicht erforderlich, das Objekt aus der Liste zu entfernen und erneut einzufügen (sehr ineffizient). Objekte sind Referenztypen. Wenn Sie einen Verweis auf das Objekt haben, aktualisieren Sie das Objekt einfach so, wie es mit dem Objekt in der Liste identisch ist.
Humbads
Noch ein Vorschlag. FindIndex gibt möglicherweise -1 zurück. In diesem Fall löst ElementAt eine Ausnahme aus.
Humbads
4

Sie können etwas tun wie:

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
quelle
0

Dies war heute eine neue Entdeckung - nachdem ich die Klassen- / Strukturreferenz gelernt hatte!

Sie können Linq und "Single" verwenden, wenn Sie wissen, dass das Element gefunden wird, da Single eine Variable zurückgibt ...

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