Nehmen wir an, ich habe eine Klasse
public class MyObject
{
public int SimpleInt{get;set;}
}
Und ich habe eine List<MyObject>
, und ich ToList()
es und dann eine der ändern SimpleInt
, wird meine Änderung wieder auf die ursprüngliche Liste weitergegeben. Mit anderen Worten, was wäre die Ausgabe der folgenden Methode?
public void RunChangeList()
{
var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
return objects[0].SimpleInt;
}
Warum?
P / S: Es tut mir leid, wenn es offensichtlich erscheint, es herauszufinden. Aber ich habe jetzt keinen Compiler bei mir ...
.ToList()
eine flache Kopie zu erstellen. Die Referenzen werden kopiert, aber die neuen Referenzen verweisen immer noch auf dieselben Instanzen wie die ursprünglichen Referenzen. Wenn Sie daran denken,ToList
können Sie keinennew MyObject()
Zeitpunkt erstellen , an dem es sich umMyObject
einenclass
Typ handelt.Antworten:
Ja, es
ToList
wird eine neue Liste erstellt. Da es sich in diesem Fall jedochMyObject
um einen Referenztyp handelt, enthält die neue Liste Verweise auf dieselben Objekte wie die ursprüngliche Liste.Das Aktualisieren der
SimpleInt
Eigenschaft eines Objekts, auf das in der neuen Liste verwiesen wird, wirkt sich auch auf das entsprechende Objekt in der ursprünglichen Liste aus.(Wenn
MyObject
als astruct
und nicht als deklariert wurde,class
enthält die neue Liste Kopien der Elemente in der ursprünglichen Liste, und das Aktualisieren einer Eigenschaft eines Elements in der neuen Liste hat keine Auswirkungen auf das entsprechende Element in der ursprünglichen Liste.)quelle
List
der Strukturen eine Zuweisung wieobjectList[0].SimpleInt=5
nicht zulässig wäre (C # -Kompilierungsfehler ). Dies liegt daran, dass der Rückgabewert desget
Accessors des Listenindexers keine Variable ist (es ist eine zurückgegebene Kopie eines Strukturwerts) und daher das Festlegen seines Mitglieds.SimpleInt
mit einem Zuweisungsausdruck nicht zulässig ist (es würde eine Kopie mutieren, die nicht beibehalten wird). . Nun, wer benutzt schon veränderbare Strukturen?foreach (var s in listOfStructs) { s.SimpleInt = 42; }
. Das wirklich böse Problem ist, wenn Sie etwas versuchen wielistOfStructs.ForEach(s => s.SimpleInt = 42)
: Der Compiler erlaubt es und der Code wird ohne Ausnahmen ausgeführt, aber die Strukturen in der Liste bleiben unverändert!Aus der Reflector'd-Quelle:
Ja, Ihre ursprüngliche Liste wird nicht aktualisiert (dh Hinzufügungen oder Entfernungen), die referenzierten Objekte jedoch.
quelle
ToList
Es wird immer eine neue Liste erstellt, die keine nachfolgenden Änderungen an der Sammlung widerspiegelt.Es werden jedoch Änderungen an den Objekten selbst angezeigt (es sei denn, es handelt sich um veränderbare Strukturen).
Mit anderen Worten, wenn Sie ein Objekt in der ursprünglichen Liste durch ein anderes Objekt ersetzen,
ToList
enthält das Objekt weiterhin das erste Objekt.Wenn Sie jedoch eines der Objekte in der ursprünglichen Liste ändern,
ToList
enthält das Objekt immer noch dasselbe (geänderte) Objekt.quelle
Die akzeptierte Antwort adressiert die Frage des OP anhand seines Beispiels korrekt. Sie gilt jedoch nur, wenn
ToList
sie auf eine konkrete Sammlung angewendet wird. Es gilt nicht, wenn die Elemente der Quellsequenz noch instanziiert werden müssen (aufgrund der verzögerten Ausführung). In letzterem Fall erhalten Sie möglicherweise bei jedem Anruf einen neuen Satz von ElementenToList
(oder listen die Reihenfolge auf).Hier ist eine Anpassung des OP-Codes, um dieses Verhalten zu demonstrieren:
Während der obige Code erfunden zu sein scheint, kann dieses Verhalten in anderen Szenarien als subtiler Fehler erscheinen. In meinem anderen Beispiel finden Sie eine Situation, in der Aufgaben wiederholt erzeugt werden.
quelle
Ja, es wird eine neue Liste erstellt. Dies ist beabsichtigt.
Die Liste enthält dieselben Ergebnisse wie die ursprüngliche Aufzählungssequenz, wird jedoch in einer dauerhaften (speicherinternen) Sammlung zusammengefasst. Auf diese Weise können Sie die Ergebnisse mehrmals verwenden, ohne die Kosten für die Neuberechnung der Sequenz zu verursachen.
Das Schöne an LINQ-Sequenzen ist, dass sie zusammensetzbar sind. Oft
IEnumerable<T>
ist das Ergebnis der Kombination mehrerer Filter-, Bestell- und / oder Projektionsvorgänge. Erweiterungsmethoden wieToList()
undToArray()
ermöglichen es Ihnen, die berechnete Sequenz in eine Standardsammlung zu konvertieren.quelle
Eine neue Liste wird erstellt, aber die darin enthaltenen Elemente verweisen auf die ursprünglichen Elemente (genau wie in der ursprünglichen Liste). Änderungen an der Liste selbst sind unabhängig, aber an den Elementen wird die Änderung in beiden Listen gefunden.
quelle
Stolpern Sie einfach über diesen alten Beitrag und denken Sie daran, meine zwei Cent hinzuzufügen. Im Zweifelsfall verwende ich im Allgemeinen schnell die GetHashCode () -Methode für jedes Objekt, um die Identitäten zu überprüfen. Also für oben -
Und antworte auf meiner Maschine -
Im Wesentlichen bleibt das Objekt, das die Liste enthält, im obigen Code dasselbe. Hoffe der Ansatz hilft.
quelle
Ich denke, das ist gleichbedeutend mit der Frage, ob ToList eine tiefe oder flache Kopie erstellt. Da ToList MyObject nicht klonen kann, muss es eine flache Kopie erstellen, sodass die erstellte Liste dieselben Referenzen wie die ursprüngliche enthält, sodass der Code 5 zurückgibt.
quelle
ToList
erstellt eine brandneue Liste.Wenn es sich bei den Elementen in der Liste um Werttypen handelt, werden sie direkt aktualisiert. Wenn es sich um Referenztypen handelt, werden alle Änderungen in den referenzierten Objekten wiedergegeben.
quelle
In dem Fall, in dem das Quellobjekt eine echte IEnumerable ist (dh nicht nur eine Sammlung, die als enumerable verpackt ist), gibt ToList () möglicherweise NICHT dieselben Objektreferenzen wie in der ursprünglichen IEnumerable zurück. Es wird eine neue Liste von Objekten zurückgegeben, aber diese Objekte sind möglicherweise nicht dieselben oder sogar gleich den Objekten, die von IEnumerable bei erneuter Aufzählung ausgegeben werden
quelle
Dadurch wird auch das ursprüngliche Objekt aktualisiert. Die neue Liste enthält Verweise auf die darin enthaltenen Objekte, genau wie die ursprüngliche Liste. Sie können die Elemente entweder ändern und das Update wird im anderen angezeigt.
Wenn Sie nun eine Liste aktualisieren (Hinzufügen oder Löschen eines Elements), wird dies nicht in der anderen Liste angezeigt.
quelle
Ich sehe nirgendwo in der Dokumentation, dass ToList () garantiert immer eine neue Liste zurückgibt. Wenn eine IEnumerable eine Liste ist, kann es effizienter sein, dies zu überprüfen und einfach dieselbe Liste zurückzugeben.
Die Sorge ist, dass Sie manchmal absolut sicher sein möchten, dass die zurückgegebene Liste! = Zur ursprünglichen Liste ist. Da Microsoft nicht dokumentiert, dass ToList eine neue Liste zurückgibt, können wir nicht sicher sein (es sei denn, jemand hat diese Dokumentation gefunden). Es könnte sich auch in Zukunft ändern, selbst wenn es jetzt funktioniert.
Neue Liste (IEnumerable enumerablestuff) gibt garantiert eine neue Liste zurück. Ich würde dies stattdessen verwenden.
quelle
ToList
beim Aufruf von a eine neueList
Listenobjektreferenz zu erstellen scheint , hat er Recht, wenn er sagt, dass dies durch die MS-Dokumentation nicht garantiert wird.IEnumerable<>.ToList()
wird tatsächlich als implementiertnew List<>(source)
und es gibt keine spezifische Überschreibung fürList<>
, sodassList<>.ToList()
tatsächlich eine neue Listenobjektreferenz zurückgegeben wird . Aber auch hier gibt es laut MS-Dokumentation keine Garantie dafür, dass sich dies in Zukunft nicht ändert, obwohl es wahrscheinlich den größten Teil des Codes da draußen brechen wird.