Ok, donc je suis un débutant en C # et j'ai appris le concept de Reference Type and Value Type. J'ai également compris que Value type est sur Stack où les Reference types sont stockés dans Heap. Et puis nous devons allouer manuellement de la mémoire à Reference type et tout ça. Mais je ne suis pas en mesure de comprendre ci-dessous le comportement. Guidez-moi s'il-vous-plaît.

Exemple 1:

    var arr1 = new int[3] { 1, 2, 3 }; // memory allocated
    var arr2 = arr1; // another variable created but pointing to same memory in Heap
    arr2[0] = 2; // value in array 2 changed
    System.Console.WriteLine("");
    foreach (var item in arr1)
    {
        System.Console.WriteLine(item);
    }
    System.Console.WriteLine("------------");

    foreach (var item in arr2)
    {
        System.Console.WriteLine(item);
    }

Sortie comme:

            arr1: 2,2,3
            arr2: 2,2,3

Conclusion: puisque les deux pointaient vers le même emplacement mémoire. Ainsi, lorsque la valeur dans Array 2 est modifiée, la valeur dans Array1 est également affectée. Jusqu'ici tout va bien.

Il existe maintenant un autre type de référence qui est une chaîne.

Considérez ci-dessous l'exemple 2:

   var Name = "Mosh";
   var FName = Name;
   FName = "Hello";
   System.Console.WriteLine(Name);
   System.Console.WriteLine(FName);

Sortie comme:

Mosh
Hello

Résultat attendu:

Hello
Hello

Depuis que j'ai changé la valeur de FName, je m'attendais à ce que la valeur Name soit également modifiée car les deux doivent pointer vers le même emplacement mémoire . C'est l'une des questions les plus simples sur SO, je suis un débutant alors soyez indulgents avec moi.

c#
2
Unbreakable 25 nov. 2017 à 04:36

3 réponses

Meilleure réponse

Votre confusion vient en partie du fait que vous voyez ces deux déclarations comme quelque peu équivalentes par nature. Ils ne sont pas!

arr2[0] = 2;

FName = "Hello";

Dans le premier cas, le tableau vers lequel pointe arr2 est modifié. Mais, la référence de arr2 à ce tableau reste inchangée. Ainsi, arr1 et arr2 continuent de pointer vers le même tableau et voient tous les deux les modifications apportées au tableau.

Dans le second cas cependant, ce n'est pas l'objet vers lequel pointe FName qui est modifié. C'est-à-dire que nous ne modifions en aucun cas la chaîne "Mosh". Au contraire, nous changeons la référence de FName pour pointer vers un emplacement mémoire différent où la chaîne immuable "Hello" réside dans le tas. Après ce point, FName ne pointe plus vers le même emplacement mémoire que Name. Name continue de pointer vers l'emplacement mémoire de "Mosh", qui reste inchangé.

2
sstan 25 nov. 2017 à 02:46

Dans le .Net Framework, une chaîne est un type de référence immuable.

Étant donné qu'une chaîne n'a pas de taille de mémoire prédéfinie (comme les types de valeur qui peuvent être stockés dans la pile), elle peut devenir volumineuse (environ 2 milliards de caractères Unicode) et nécessite une allocation de mémoire dynamique. Lorsqu'un objet String est créé, la valeur réelle est stockée dans la mémoire dynamique, le Heap.

Immuable signifie qu'il ne peut pas être modifié après sa création. Chaque modification apportée à une chaîne créera une nouvelle chaîne. C'est pourquoi toutes les méthodes de manipulation String renvoient une chaîne.

Les types de référence ont des frais généraux sur la construction et la destruction et garbage collection, car ils sont créés sur le tas. Types de valeur d'autre part, ont une surcharge sur les appels de méthode (si la taille des données plus grand qu'un pointeur), car tout l'objet est copié plutôt que juste un pointeur. Parce que les chaînes peuvent être beaucoup plus grandes que la taille d'un pointeur, ils sont conçus comme des types de référence. Réf.

Dans votre cas: lorsque vous attribuez un nom à FName: FName = Name les deux chaînes font référence au même objet (comme indiqué dans l'exemple de code) qui contient la chaîne "Mosh" dans le tas. Une fois que FName a été défini sur une autre valeur de chaîne, il référence un emplacement mémoire différent qui stocke la nouvelle chaîne "Hello". Le nom continue de pointer vers l'emplacement mémoire d'origine qui stocke "Mosh" et reste inchangé.

Ce comportement de String en tant que type valeur est moins évident lorsqu'il est utilisé comme paramètre qui met à jour la valeur dans la fonction. Tant que le paramètre String n'est pas fourni par référence, sa valeur d'origine ne sera pas modifiée (voir l'exemple).

using System;

public class Program
{
    public static void Main()
    {
        var Name = "Mosh";
        var FName = Name;
        Console.WriteLine(Object.ReferenceEquals(Name,FName));

        FName = "Hello";
        System.Console.WriteLine(Name);
        System.Console.WriteLine(FName);
        Console.WriteLine(Object.ReferenceEquals(Name,FName));

        TestFunc(Name);
        System.Console.WriteLine(Name); 

        RefFunc(ref FName);
        System.Console.WriteLine(FName);    
    }

    public static void TestFunc(string test)
    {
        test = "after passing";
    }

    public static void RefFunc(ref string test)
    {
        test = "after passing";
    }
}
3
wp78de 25 nov. 2017 à 03:22

Une chaîne dans un type de référence oui, mais selon la conception de C #, elle se comportera plus ou moins comme les autres types de primitives / valeurs.

Pour obtenir l'effet dont vous avez parlé, vous devez spécifier qu'une valeur est un pointeur, quelque chose de similaire à: string* PName = Name;

Votre question, "Est-il prudent de dire qu'ils pointent vers le même emplacement en mémoire?" Je ne suis pas vraiment sûr, bien que je sache que les chaînes n'ont pas d'adresse fixe en mémoire, vous ne pouvez donc pas utiliser "&" ou "GetHashCode" comme vous pouvez le tester sur des entiers ou d'autres types.

Modifier 1:

Eh bien, je serai l'oncle d'un singe, tu as raison. Essaye ça:

Console.WriteLine(Object.ReferenceEquals(Name,FName)
0
Jacob M. 25 nov. 2017 à 02:52
47481890