2016-07-13 8 views
-1

Ich habe gerade diese Verwirrung den ganzen Tag über im Kopf. Ich bin sehr verwirrt zwischen Referenz und Werttyp, der an eine Methode übergeben wird.Der Unterschied zwischen der Übergabe eines Referenztyps und eines Werttyps als Argument an eine Methode

Sagen, ich habe 2 Klassen Class A und Klasse B, die jeweils referenzieren und Werttypen entsprechen.

public Class A 
{ 
    public static void main(string[] args) 
    { 
     String s = “hello”; 
     String w = Changestring(s); 
     String x = s; 
    } 

    private string Changestring(string s) 
    { 
     s += “Hi”; 
     return s; 
    } 
} 

.

public Class B 
{ 
    public static void main(string[] args) 
    { 
     int s = 99; 
     int w = Changeint(s); 
     int x = s; 
    }  

    private int Changeint(int s) 
    { 
      s += 30; 
      return s; 
    } 
} 

Ich bin verwirrt einen Referenztyp (string) und Wertetyp (int) als Argument für eine Funktion zwischen geben. Wenn ich ein solches Programm ausführen, ist das x für Zeichenfolge (Referenztyp) "Hallo" selbst und x für Werttyp ist 99. Sollte x "HelloHi" statt "Hallo" sein, da es ein Referenztyp ist?

Bitte helfen Sie mir diese einfachen Zweifel zu löschen.

+4

's + = "Hallo";' ist eine Abkürzung für 's = s + "Hallo";'. Sie erstellen eine neue Zeichenfolge und nicht die vorhandene. Daher das Ergebnis, das Sie sehen –

+1

Sie führt eine neue Referenzzeichenfolge "s" in der 'ChangeString()' Methode ein, so dass es sich von der Zeichenfolge 's' in der' main' Methode unterscheidet. Wenn Sie den vorhandenen mutieren wollten, hätten Sie 'ref' verwenden sollen. – denchu

+0

[Vielleicht möchten Sie auch dies lesen] (http://stackoverflow.com/a/30369126/3094533) –

Antwort

4

Neben Reference Type und Value Type gibt es Mutable Type und Immutable Type.

Immutable bedeutet, dass Objekt nicht und wird nicht nach der Initialisierung geändert werden. Als Ergebnis nur Ihre Aussage produziert neue Zeichenfolge, ändert jedoch nicht die ursprüngliche Zeichenfolge

s + = "Hallo";

Das hello Stringobjekt bleibt hello. Änderung ist, dass s mit einem neuen Objekt helloHi zugewiesen wird.


Sie sind unglücklich genug string als Beispiel.

Versuchen Sie, in Ihrem Beispiel veränderbare Typen wie StringBuilder zu verwenden.

public class C 
{ 
    public static void Main(string[] args) 
    { 
     StringBuilder s = new StringBuilder("hello"); 
     StringBuilder w = Changestring(s); 
     StringBuilder x = s; 
    } 

    private static StringBuilder Changestring(StringBuilder s) 
    { 
     s.Append("Hi"); 
     return s; 
    } 
} 
+0

Eigentlich hat die Unveränderlichkeit der Zeichenfolge nichts mit dem Ergebnis zu tun. Der wahre Grund ist, was Koozik in seinem Kommentar geschrieben hat: 's + =" Hi ";' ist eine Abkürzung für 's = s +" Hi ";' - so ist das Problem die Zuweisung eines neuen Wertes zu der an die Variable übergebenen Variablen Methode. [Meine Antwort auf einen ähnlichen Beitrag wird dies beweisen.] (Http://stackoverflow.com/a/30369126/3094533) –

+0

Es bedeutet also ** Referenz ** -Typen und ** Value ** -Typen, wenn sie als Argument übergeben werden eine Funktion hat das gleiche Verhalten und das Verhalten hängt nur von veränderlichen und unveränderlichen ab? – ViVi

+0

@ViVi 'Reference-Immutable' Typ verhält sich genauso wie' Value' Typ. – Tommy

2

zuerst zu wissen, nach Wert vorbei nicht Änderung Anfangsvariablenwert, wobei durch Bezugnahme vorbei auch Anfangs durch Verfahren verwiesen Variablenwert ändert.

Standardmäßig wird int als Werttyp behandelt, daher wird es als Wert übergeben. Allerdings String sogar als eine Klasse (Referenztyp) deklariert, ist es standardmäßig mit sealed Modifizierer unveränderlich, so behandelt als Übergabe von Wert und Hinzufügen neuer Zeichen erstellen Sie einfach neue Instanz von String, nicht ändern aktuelle.

Durch das Hinzufügen ref Stichwort Sie int Verhalten passing by-reference ändern können:

public Class B 
{ 
    public static void main(string[] args) 
    { 
     int s = 99; 
     int w = Changeint(s); // w has changed 
     int x = s; // s has also changed 
    }  

    private int Changeint(ref int s) 
    { 
      s += 30; // result = 129 
      return s; 
    } 
} 

Für die Klasse A, benötigen Sie einen Stringbuilder-Instanz "helloHi" zu erreichen:

public Class A 
{ 
    public static void main(string[] args) 
    { 
     String s = “hello”; 
     String w = Changestring(s); 
     String x = w; // if you assign s to x, you will just get "hello" 
    } 

    private string Changestring(string s) 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.Append(s); 
     sb.Append(“Hi”); 
     return sb.ToString(); // "helloHi" 
    } 
} 

CMIIW .

+0

Bekam den Punkt. Danke für die Antwort. Wenn ich also einen String Builder in meiner Hauptmethode habe und denselben sb an eine Funktion ** ChangeString ** übergebe und Operationen an sb selbst (Text anhängen) ohne eine neue Instanz von stringbuilder zu erstellen und keinen Wert zurückließe, wird der sb in main-Methode erstellt enthalten den angehängten Text in der Methode? – ViVi

+0

'versiegelt' verhindert, dass eine Klasse unterklassifiziert wird, sie macht sie nicht unveränderlich. Unveränderlichkeit hängt davon ab, wie eine Klasse implementiert wird. –

2

In C#, alle Argumente zu Verfahren gesendet werden, vorbei von Wert, es sei denn, sie übergeben werden, indem entweder die ref oder out Schlüsselwörter.

Dies umfasst Argumente, die Werttypen, Referenztypen, veränderbare und unveränderliche Typen sind.

Wenn ein Referenzart Argument übergeben sich auf ein Verfahren, was tatsächlich passiert, ist, dass die Referenz des Arguments Wert von geben wird.

Dies bedeutet, dass das Verfahren eine neue Referenz auf das Argument gilt tatsächlich an sie übergibt.
Jede Änderung des Zustands dieses Arguments wird daher auch bei Verwendung der Referenz von außerhalb der Methode angezeigt.
Wenn Sie jedoch der Referenz innerhalb der Methode einen neuen Wert zuweisen, spiegelt sie die Referenz nicht außerhalb der Methode wider.

Für eine bessere, ausführlichere Erklärung, lesen Sie Jon Skeets Parameter passing in C# Artikel.

Sie können dies nicht mit einem unveränderlichen Typ testen, da unveränderliche Typen per Definition nicht geändert werden können.

Sie können jedoch testen diese mit jedem wandelbaren Typ:

public static void Main() 
{ 
    var x = new List<int>(); 
    x.Add(1); 
    Add(x, 2); 
    Console.WriteLine(x.Count.ToString()); // will print "2"; 
    AddRef(ref x, 3); 
    Console.WriteLine(x.Count.ToString()); // will print "1"; 
    Add3(x, 1, 2, 3); 
    Console.WriteLine(x.Count.ToString()); // will also print "1"; 
    Add3Ref(ref x, 1, 2, 3); 
    Console.WriteLine(x.Count.ToString()); // will print "3"; 
} 

static void Add(List<int> list, int value) 
{ 
    // adding an item to the list, thus chaning the state of the list. 
    // this will reflect on the list sent to the method, 
    // since a List is a reference type. 
    list.Add(value); 
} 

static void AddRef(ref List<int> list, int value) 
{ 
    list = new List<int>(); // same as the s += “Hi”; in the question 
    // Adding the value to the list. 
    // Note that this change will reflect on the list passed to the method, 
    // since it is passed using the ref keyword. 
    list.Add(value); 
} 


static void Add3(List<int> list, int value1, int value2, int value3) 
{ 
    list = new List<int>(); // same as the s += “Hi”; in the question 

    // these values are added to the new list. 
    // since the reference to the list was passed by value, 
    // it WILL NOT effect the list sent to the method. 
    list.Add(value1); 
    list.Add(value2); 
    list.Add(value3); 
} 

static void Add3Ref(ref List<int> list, int value1, int value2, int value3) 
{ 
    list = new List<int>(); // same as the s += “Hi”; in the question 
    // these values are added to the new list. 
    // since the list was passed by reference, 
    // it WILL effect the list sent to the method. 
    list.Add(value1); 
    list.Add(value2); 
    list.Add(value3); 
} 

You can see for yourself on this fiddle.

Verwandte Themen