Assignation de la chaîne en C#

il y a quelques semaines, j'ai découvert que les chaînes en C# sont définies comme des types de référence et non des types de valeur. Au début, j'étais confus à ce sujet, mais après quelques lectures, j'ai soudain compris pourquoi il est important de stocker les cordes sur le tas et non sur la pile - parce qu'il serait très inefficace d'avoir une très grande corde qui est copiée sur un nombre imprévisible de cadres de pile. Je suis entièrement d'accepter cela.

je pense que ma compréhension est presque complète, mais là est un élément qui me manque - ce que le langage ne les chaînes utilisent pour garder immuable? Pour illustrer avec un exemple de code:

string valueA = "FirstValue";
string valueB = valueA;
valueA = "AnotherValue";

Assert.AreEqual("FirstValue", valueB); // Passes

Je ne comprends pas quelle caractéristique de langue fait une copie de valueA quand je l'attribue à valueB. Ou peut-être, la référence à valueA ne change pas quand je l'attribue à valueB, seulement valueA obtient une nouvelle référence à lui-même quand je mets la chaîne. Comme c'est un type d'instance, je ne comprends pas pourquoi cela fonctionne.

je comprends que vous pouvez surcharger, par exemple, le == et != opérateurs, mais je ne semble pas trouver de documentation sur la surcharge des opérateurs=. Quelle est l'explication?

20
demandé sur Peter Mortensen 2011-06-04 15:50:11

3 réponses

quelle fonctionnalité de langue les chaînes de caractères utilisent-elles pour les garder immuables?

Ce n'est pas une fonctionnalité du langage. C'est la façon dont la classe est définie.

Par exemple,

class Integer {
    private readonly int value;

    public int Value { get { return this.value; } }
    public Integer(int value) { this.value = value; } }
    public Integer Add(Integer other) {
        return new Integer(this.value + other.value);
    }
}

est comme int sauf que c'est un type de référence, mais il est immuable. Nous défini. On peut le Définir comme mutable aussi:

class MutableInteger {
    private int value;

    public int Value { get { return this.value; } }
    public MutableInteger(int value) { this.value = value; } }
    public MutableInteger Add(MutableInteger other) {
        this.value = this.value + other.value;
        return this;
    } 
}

Voir?

je ne comprends pas ce langage fait une copie de valueA quand je l'attribuer à valueB.

Il ne copie pas les string, il copie la référence. stringtype de référence. Cela signifie que les variables de type string s sont des lieux de stockage dont les valeurs sont des références. Dans ce cas, leurs valeurs sont des références à des instances de string. Lorsque vous assignez une variable de type string à l'autre de type string, la valeur est copiée. Dans ce cas, la valeur est une référence et il est copié par l' affectation. C'est vrai pour n'importe quel type de référence, pas seulement string ou seulement des types de référence immuables.

Ou peut-être, la référence à valueA ne change pas lorsque je l'attribuer à valueB, seulement valueA obtient une nouvelle référence à lui-même quand je mets la chaîne.

Non, les valeurs de valueA et valueB reportez-vous à la même instance de string. Leurs valeurs sont des références, et ces valeurs sont égales. Si vous pouviez en quelque sorte muter* l'instance de string visées par valueA, le référent des deux valueA et valueB verrait cette mutation.

Comme c'est un type d'instance, je ne comprends pas pourquoi cela fonctionne.

il n'existe pas de type d'instance.

en gros, string s sont des types de référence. Mais string sont immuables. Lorsque vous muter un string, ce qui se passe est que vous obtenez une référence à une nouvelle chaîne qui est le résultat de la mutation vers le déjà existant string.

string s = "hello, world!";
string t = s;
string u = s.ToUpper();

Ici s et t sont des variables dont les valeurs se réfèrent à la même instance de string. Le referrent de s n'est pas muté par l'appel à String.ToUpper. Au lieu de cela, s.ToUpper fait une mutation du référent de s et renvoie une référence à une instance de string qu'il crée dans le processus d'appliquer la mutation. Nous attribuons cette référence à u.

je comprends que vous ne pouvez surcharge, par exemple, l' == et != opérateurs, mais je ne semble pas trouver de documentation sur la surcharge des opérateurs=.

Vous ne pouvez pas surcharger =.

* Vous pouvez, avec quelques astuces. Les ignorer.

12
répondu jason 2011-06-04 12:06:34

tout d'abord, votre exemple fonctionnera de la même façon pour toutes les variables de référence, pas seulement les chaînes.

Ce qui se passe est:

string valueA = "FirstValue"; //ValueA is referenced to "FirstValue"  
string valueB = valueA; //valueB references to what valueA is referenced to which is "FirstValue"  
valueA = "AnotherValue"; //valueA now references a new value: "AnotherValue"
Assert.AreEqual("FirstValue", valueB); // remember that valueB references "FirstValue"

immutabilité est un concept différent. Cela signifie que la valeur elle-même ne peut pas être changé.

Cela permettra de montrer dans une situation comme ceci:

string valueA = "FirstValue"; //ValueA is referenced to "FirstValue"  
string valueB = valueA; //valueB references to what valueA is referenced to which is "FirstValue"  
valueA.Replace('F','B'); //valueA will now be: "BirstValue"
Assert.AreEqual("FirstValue", valueB); // remember that valueB references "FirstValue"

c'est à cause de L'immuabilité de la chaîne, valueA ne change pas la chaîne elle-même... Il crée un nouveau COPY avec les changements et les références.

6
répondu Yochai Timmer 2011-06-04 12:01:41

C'est exact. Comme les chaînes sont immuables, il n'y a aucun problème à avoir deux variables se référant au même objet string. Quand vous assignez une nouvelle chaîne à l'un d'eux, c'est la référence qui est remplacée, pas l'objet string.

je n'arrive pas à trouver tout de la documentation sur la surcharge de l' = opérateur.

cela n'est pas dû à un défaut de votre part, c'est parce qu'il n'y a aucun moyen de surcharger l'opérateur d'assignation en C#.

= operator est assez simple, il prend la valeur du côté droit et assigne à la variable du côté gauche. Si c'est un type de référence, la valeur est la référence, donc c'est ce qui est assigné.

2
répondu Guffa 2011-06-04 12:17:54