Search code examples
c#stringvalue-typereference-type

Why reference types inside structs behave like value types?


I am a beginner to C# programming. I am now studying strings, structs, value types and reference types. As accepted answers in here and in here, strings are reference types that have pointers stored on stack while their actual contents stored on heap. Also, as claimed in here, structs are value types. Now I try to practice with structs and strings with a small example:

struct Person
{
    public string name;
}

class Program
{
    static void Main(string[] args)
    {
        Person person_1 = new Person();
        person_1.name = "Person 1";

        Person person_2 = person_1;
        person_2.name = "Person 2";

        Console.WriteLine(person_1.name);
        Console.WriteLine(person_2.name);
    }
}

The above code snippet outputs

Person 1
Person 2

that makes me confused. If strings are reference types and structs are value types then person_1.name and person_2.name should point to the same space region on heap, shouldn't them?


Solution

  • strings are reference types that have pointers stored on stack while their actual contents stored on heap

    No no no. First off, stop thinking about stack and heap. This is almost always the wrong way to think in C#. C# manages storage lifetime for you.

    Second, though references may be implemented as pointers, references are not logically pointers. References are references. C# has both references and pointers. Don't mix them up. There is no pointer to string in C#, ever. There are references to string.

    Third, a reference to a string could be stored on the stack but it could also be stored on the heap. When you have an array of references to string, the array contents are on the heap.

    Now let's come to your actual question.

        Person person_1 = new Person();
        person_1.name = "Person 1";
        Person person_2 = person_1; // This is the interesting line
        person_2.name = "Person 2";
    

    Let's illustrate what the code does logically. Your Person struct is nothing more than a string reference, so your program is the same as:

    string person_1_name = null; // That's what new does on a struct
    person_1_name = "Person 1";
    string person_2_name = person_1_name; // Now they refer to the same string
    person_2_name = "Person 2"; // And now they refer to different strings
    

    When you say person2 = person1 that does not mean that the variable person1 is now an alias for the variable person2. (There is a way to do that in C#, but this is not it.) It means "copy the contents of person1 to person2". The reference to the string is the value that is copied.

    If that's not clear try drawing boxes for variables and arrows for references; when the struct is copied, a copy of the arrow is made, not a copy of the box.