Geben Sie 'string' als Argument in die C # -Funktion ein

7

Der string -Typ in C # ist ein Referenztyp, und wenn ein Referenzargument nach Wert übergeben wird, wird der Verweis kopiert, sodass ich den ref -Modifikator nicht verwenden muss. Allerdings muss ich den Modifizierer ref verwenden, um die Eingabe string zu ändern. Warum ist das?

%Vor%     
prosseek 29.05.2011, 05:46
quelle

7 Antworten

12

Der Grund dafür, dass Sie den String-Parameter referenzieren müssen, besteht darin, dass Sie, obwohl Sie einen Verweis auf ein String-Objekt übergeben, nur den aktuell im Parameter variablen gespeicherten Verweis ersetzen . Mit anderen Worten, Sie haben geändert, worauf der Parameter verweist, aber das ursprüngliche Objekt ist unverändert.

Wenn Sie den Parameter referenzieren, haben Sie der Funktion gesagt, dass der Parameter tatsächlich ein Alias ​​für die übergebene Variable ist, so dass die Zuweisung den gewünschten Effekt hat.

BEARBEITEN : Beachten Sie, dass while eine unveränderliche Referenz ist, die hier nicht relevant ist. Da Sie nur versuchen, ein neues Objekt zuzuordnen (in diesem Fall das Zeichenfolgenobjekt "modifiziert"), funktioniert Ihr Ansatz nicht mit dem Referenztyp any . Betrachten Sie zum Beispiel diese geringfügige Änderung an Ihrem Code:

%Vor%

Nun ist der Array-Test fehlgeschlagen, weil Sie der non-ref-Parametervariablen ein neues Objekt zuweisen.

    
dlev 29.05.2011, 05:51
quelle
6

Es hilft, string mit einem Typ zu vergleichen, der wie string ist, aber veränderbar ist. Lassen Sie uns ein kurzes Beispiel mit StringBuilder sehen:

%Vor%

Dies erzeugt:

%Vor%

Wir sehen also, dass es für einen veränderbaren Typ, dh einen Typ, dessen Wert geändert werden kann, möglich ist, einen Verweis auf diesen Typ an eine Methode wie ChangeBuilder zu übergeben und nicht ref oder out und Nach dem Aufruf haben wir den Wert noch geändert.

Und beachten Sie, dass wir zu keinem Zeitpunkt builder auf einen anderen Wert in ChangeBuilder gesetzt haben.

Im Gegensatz dazu, wenn wir dasselbe mit string machen:

%Vor%

Dies erzeugt:

%Vor%

Warum? Weil wir in TryToChangeString nicht wirklich den Inhalt der Zeichenfolge ändern, auf die die Variable s verweist, ersetzen wir s durch eine völlig neue Zeichenfolge. Außerdem ist s eine lokale Variable für TryToChangeString und ersetzt somit den Wert von s innerhalb die Funktion hat keine Auswirkung auf die Variable, die an den Funktionsaufruf übergeben wurde.

Da ein string unveränderlich ist, gibt es keine Möglichkeit, die Anruferzeichenfolge zu beeinflussen, wenn Sie ref oder out nicht verwenden.

Letztendlich macht das letzte Beispiel was wir wollen mit string :

%Vor%

Dies erzeugt:

%Vor%

Der ref -Parameter macht tatsächlich die zwei s -Variablen Aliase füreinander. Es ist, als wären sie die gleiche Variable .

    
Rick Sladkey 29.05.2011 06:18
quelle
5

Strings sind unveränderlich - Sie ändern die Zeichenfolge nicht, sondern ersetzen das Objekt durch den Referenzpunkt durch einen anderen.

Vergleichen Sie das mit z. B. einer Liste: Um Artikel hinzuzufügen, brauchen Sie nicht ref. Um die gesamte Liste durch ein anderes Objekt zu ersetzen, benötigen Sie ref (oder out).

    
Michael Stum 29.05.2011 05:49
quelle
3

Dies ist der Fall für alle unveränderlichen Typen. string ist zufällig unveränderlich.

Um den unveränderlichen Typ außerhalb der Methode zu ändern, müssen Sie die Referenz ändern. Daher muss entweder ref oder out außerhalb der Methode wirksam sein.

Hinweis: Es ist erwähnenswert, dass Sie in Ihrem Beispiel einen bestimmten Fall aufrufen, der nicht mit dem anderen Beispiel übereinstimmt: Sie verweisen tatsächlich auf eine andere Referenz, anstatt einfach die vorhandene Referenz zu ändern. Wie von dlev (und dem Skeet selbst in meinen Kommentaren) angemerkt, wenn Sie das Gleiche für alle anderen Typen (zB val = new int[1] ), einschließlich veränderbarer, getan haben, werden Sie Ihre Änderungen "verlieren" Sobald die Methode zurückkehrt, weil sie nicht mit demselben Objekt im Speicher passiert ist, außer Sie verwenden ref oder out wie Sie es mit string oben getan haben.

Um hoffentlich zu verdeutlichen:

Sie übergeben einen Zeiger, der auf Ihr Objekt im Speicher zeigt. Ohne ref oder out wird ein neuer Zeiger erzeugt, der genau auf die gleiche Stelle zeigt, und alle Änderungen erfolgen mit dem kopierten Zeiger. Mit ihnen wird derselbe Zeiger verwendet und alle Änderungen am Zeiger werden außerhalb der Methode angezeigt.

Wenn Ihr Objekt änderbar ist, bedeutet dies, dass es geändert werden kann, ohne eine neue Instanz des Objekts zu erstellen. Wenn Sie eine neue Instanz erstellen, müssen Sie auf eine andere Stelle im Speicher verweisen, was bedeutet, dass Sie den Zeiger ändern müssen.

Wenn Ihr Objekt jetzt unveränderlich ist, bedeutet dies, dass es nicht geändert werden kann, ohne eine neue Instanz zu erstellen.

In Ihrem Beispiel haben Sie eine neue Instanz von string (gleich "modified" ) erstellt und dann den Zeiger ( input ) so geändert, dass er auf diese neue Instanz verweist. Für das Array int haben Sie einen der 10 Werte geändert, auf die effektiv val zeigt, und die nicht mit dem Zeiger von val verwechselt werden muss - es geht einfach dorthin, wo Sie wollen (das erste Element des Arrays) ) und modifiziert dann diesen ersten Wert in-place.

Ein ähnlicheres Beispiel wäre (gestohlen von dlev, aber das ist, wie man sie wirklich vergleichbar macht):

%Vor%

Beide Funktionen ändern den Zeiger ihrer Parameter. Nur weil Sie ref verwendet haben, "erinnert" sich input an seine Änderungen, denn wenn der Zeiger geändert wird, ändert er den übergebenen Zeiger und nicht nur eine Kopie davon.

val ist immer noch ein Array von 10 int s außerhalb der Funktion, und val[0] ist immer noch 1, weil " val " in Function2 ein anderes Zeiger, der ursprünglich auf den gleichen Ort wie% val von Main verweist, aber nach dem Erstellen des neuen Arrays auf eine andere Stelle zeigt (der andere Zeiger zeigt auf das neue Array und der ursprüngliche Zeiger zeigt weiter zum selben Ort).

Wenn ich ref mit dem Array int verwendet hätte, dann hätte sich das geändert. Und es hätte sich auch in der Größe verändert.

    
pickypg 29.05.2011 05:49
quelle
0

Die Verwirrung besteht darin, dass Ref-Typreferenzen standardmäßig als Wert übergeben werden. Um die Referenz selbst (auf die das Objekt verweist) zu ändern, müssen Sie die Referenz als Referenz übergeben - mit ref .

In Ihrem Fall behandeln Sie Strings - wenn Sie einer Variablen einen String zuweisen (oder anhängen usw.), wird der Verweis geändert, da Strings unveränderlich sind. Es gibt auch keine Möglichkeit, dies zu vermeiden. Verwenden Sie daher ref .

    
BrokenGlass 29.05.2011 05:48
quelle
0

Ein besseres Beispiel für Neulinge:

%Vor%

... gibt "one" aus.

Warum? Weil Sie dem Zeiger b eine ganz neue Zeichenfolge zuweisen.

    
Vercas 30.05.2011 13:27
quelle
0

Sie haben Recht. Arrays und Zeichenfolgen sind Referenztypen. Aber um ehrlich zu sein und ähnliches Verhalten zu vergleichen, sollte man so etwas schreiben:

%Vor%

In Ihrem Beispiel führen Sie jedoch eine Schreiboperation in einem Element eines eindimensionalen C # -Arrays über den Verweis val durch.

    
bruziuz 23.07.2015 21:22
quelle

Tags und Links