Schauen Sie sich folgendes Programm an:
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
Ich nahm an myList
, dass vorbei ref
gegangen wäre, und die Ausgabe würde
3
4
Die Liste wird zwar "von ref übergeben", aber nur die sort
Funktion wird wirksam. Die folgende Aussage myList = myList2;
hat keine Wirkung.
Die Ausgabe ist also tatsächlich:
10
50
100
Können Sie mir helfen, dieses Verhalten zu erklären? Wenn es tatsächlich myList
nicht von ref übergeben wird (wie es scheint, wenn es myList = myList2
nicht wirksam wird), wie wird myList.Sort()
es wirksam?
Ich ging davon aus, dass selbst diese Aussage nicht wirksam wird und die Ausgabe wie folgt lautet:
100
50
10
c#
list
pass-by-reference
nmdr
quelle
quelle
ChangeList
, eine zurückzugeben,List<int>
anstatt eine zu sein,void
wenn tatsächlich eine neue Liste erstellt wird.Antworten:
Sie übergeben einen Verweis auf die Liste , aber Sie übergeben die Listenvariable nicht als Referenz. Wenn Sie also
ChangeList
den Wert der Variablen aufrufen (dh die Referenz - denken Sie an "Zeiger"), wird kopiert - und ändert sich in den Wert des Parameter im InnerenChangeList
werden von nicht gesehenTestMethod
.Versuchen:
Dies übergibt dann einen Verweis auf die lokale Variable
myRef
(wie in deklariertTestMethod
); Wenn Sie jetzt den Parameter im Inneren neuChangeList
zuweisen, weisen Sie auch die Variable im Inneren neu zuTestMethod
.quelle
ChangeList
, wird nur die Referenz kopiert - es ist dasselbe Objekt. Wenn Sie das Objekt auf irgendeine Weise ändern, wird die Änderung für alles angezeigt , das auf dieses Objekt verweist.Zunächst kann es wie folgt grafisch dargestellt werden:
Dann wird die Sortierung angewendet
myList.Sort();
Als Sie das getan haben
myList' = myList2
, haben Sie schließlich die Referenz verloren, aber nicht das Original, und die Sammlung blieb sortiert.Wenn Sie als Referenz (
ref
) verwenden, wirdmyList'
undmyList
wird dieselbe (nur eine Referenz).Hinweis: Ich verwende
myList'
, um den Parameter darzustellen, in dem Sie verwendenChangeList
(weil Sie den gleichen Namen wie das Original angegeben haben).quelle
Hier ist ein einfacher Weg, es zu verstehen
Ihre Liste ist ein Objekt, das auf einem Heap erstellt wurde. Die Variable
myList
ist eine Referenz auf dieses Objekt.In C # übergeben Sie niemals Objekte, sondern deren Referenzen als Wert.
Wenn Sie über die übergebene Referenz in
ChangeList
(z. B. beim Sortieren) auf das Listenobjekt zugreifen , wird die ursprüngliche Liste geändert.Die Zuweisung für die
ChangeList
Methode erfolgt zum Wert der Referenz, daher werden keine Änderungen an der ursprünglichen Liste vorgenommen (immer noch auf dem Heap, aber nicht mehr auf der Methodenvariablen referenziert).quelle
Dieser Link hilft Ihnen beim Verständnis der Referenzübergabe in C #. Wenn ein Objekt vom Referenztyp als Wert an eine Methode übergeben wird, können grundsätzlich nur Methoden, die für dieses Objekt verfügbar sind, den Inhalt des Objekts ändern.
Beispielsweise ändert die List.sort () -Methode den Listeninhalt. Wenn Sie jedoch derselben Variablen ein anderes Objekt zuweisen, ist diese Zuweisung für diese Methode lokal. Deshalb bleibt myList unverändert.
Wenn wir ein Objekt vom Referenztyp mit dem Schlüsselwort ref übergeben, können wir derselben Variablen ein anderes Objekt zuweisen, das das gesamte Objekt selbst ändert.
(Bearbeiten: Dies ist die aktualisierte Version der oben verlinkten Dokumentation.)
quelle
C # erstellt nur eine flache Kopie, wenn der Wert übergeben wird, es sei denn, das betreffende Objekt wird ausgeführt
ICloneable
(was anscheinend dieList
Klasse nicht tut).Dies bedeutet, dass es das
List
selbst kopiert , die Verweise auf die Objekte in der Liste jedoch gleich bleiben. Das heißt, die Zeiger verweisen weiterhin auf dieselben Objekte wie das OriginalList
.Wenn Sie die Werte der Dinge ändern, auf die Ihre neuen
List
Referenzen verweisen, ändern Sie auch das OriginalList
(da es auf dieselben Objekte verweist). Sie ändern dann jedoch diemyList
Verweise vollständig auf eine neueList
, und jetztList
verweist nur das Original auf diese Ganzzahlen.Weitere Informationen finden Sie im Abschnitt Übergeben von Referenztypparametern in diesem MSDN-Artikel unter "Übergeben von Parametern" .
"Wie klone ich eine generische Liste in C # ? " Von StackOverflow beschreibt, wie eine tiefe Kopie einer Liste erstellt wird.
quelle
Ich stimme zwar dem zu, was alle oben gesagt haben. Ich habe eine andere Sicht auf diesen Code. Grundsätzlich weisen Sie die neue Liste der lokalen Variablen myList zu, nicht der globalen. Wenn Sie die Signatur von ChangeList (List myList) in private void ChangeList () ändern, wird die Ausgabe von 3, 4 angezeigt.
Hier ist meine Argumentation ... Auch wenn die Liste als Referenz übergeben wird, stellen Sie sich vor, Sie übergeben eine Zeigervariable als Wert. Wenn Sie ChangeList (myList) aufrufen, übergeben Sie den Zeiger an (Global) myList. Dies wird nun in der (lokalen) myList-Variablen gespeichert. Jetzt zeigen Ihre (lokale) myList und (globale) myList auf dieselbe Liste. Jetzt sortieren Sie => es funktioniert, weil (lokale) myList auf die ursprüngliche (globale) myList verweist. Als Nächstes erstellen Sie eine neue Liste und weisen den Zeiger Ihrer (lokalen) myList zu. Sobald die Funktion beendet wird, wird die (lokale) myList-Variable zerstört. HTH
quelle
Verwenden Sie das
ref
Schlüsselwort.Schauen Sie sich hier die endgültige Referenz an , um die Übergabeparameter zu verstehen.
Um genau zu sein, Blick auf diesem , um das Verhalten des Codes zu verstehen.
BEARBEITEN:
Sort
arbeitet mit derselben Referenz (die als Wert übergeben wird) und daher werden die Werte geordnet. Das Zuweisen einer neuen Instanz zum Parameter funktioniert jedoch nicht, da der Parameter als Wert übergeben wird, es sei denn, Sie geben einref
.Mit Putting
ref
können Sie den Zeiger auf den Verweis auf eine neue Instanz vonList
in Ihrem Fall ändern . Ohneref
können Sie an dem vorhandenen Parameter arbeiten, aber nicht auf etwas anderes verweisen.quelle
Für ein Objekt vom Referenztyp sind zwei Teile des Speichers zugeordnet. Einer im Stapel und einer im Haufen. Das Teil im Stapel (auch als Zeiger bezeichnet) enthält einen Verweis auf das Teil im Heap, in dem die tatsächlichen Werte gespeichert sind.
Wenn das Schlüsselwort ref nicht verwendet wird, wird nur eine Kopie des Teils im Stapel erstellt und an die Methode übergeben - Verweis auf dasselbe Teil im Heap. Wenn Sie also etwas im Heap-Teil ändern, bleiben diese Änderungen erhalten. Wenn Sie den kopierten Zeiger ändern, indem Sie ihn so zuweisen, dass er auf eine andere Stelle im Heap verweist, wirkt sich dies nicht auf den Ursprungszeiger außerhalb der Methode aus.
quelle