Search code examples
c#value-typereference-type

Value and Reference types confusion


I was on every website about this topic and was reading the past few days through Jon Skeets´s article about References and Values and Parameter passing. I understood the concept of those two types, what they stand for and the difference to Value and Reference parameters what is another specification.

I understand how this works and how you can use it, but i dont understand something everbody says about this topic. You all out there say that for example int is a value type and string is a reference type. But according to my understanding the type basically just depends on the kind of class in which they got declared.

Have a look at this code snippet to understand what i mean:

public struct IntHolder
{
   public int number;
}

IntHolder first = new IntHolder();
first.number = 5;
IntHolder second = first;
first.number = 6;

Now second.number has the value 5. If you change struct to class, number will act like a reference type, so it doesnt matter at all that int is in generell a value type, its just about the type of the class. Same example goes for string, etc... .

So apparently the type of the class where the object gets declared sets the type of its objects or i missunderstand a core concept. Please either correct me and help me to understand it correct or tell what is the sense behind saying that int string, etc...has a special type even though it does not matter when they get initialised, so basically always.


Solution

  • This has nothing to do with the type of the field you are changing. What is relevant here is indeed just the kind of the parent type:

    IntHolder first = new IntHolder();
    IntHolder second = first;
    

    Depending on the kind of IntHolder this has two different effects:

    For value types (struct), this creates a copy. The data of the value type object lives with the object, so all of it is copied. It’s kind of equivalent to this:

    IntHolder second = new IntHolder();
    second.number = first.number;
    // and all other fields (visible or not) are copied too
    

    This means that an assignment to a field of the copied value type will overwrite that value without affecting the original object. It’s like how a local variable behaves:

    var x = 5;
    var y = 2;
    y = 3; // this does not change x
    

    However, when the type is a reference type, the assignment second = first just copies the reference. The underlying object where the values are kept are the same for both. So changes to either object affect the other—because there is no “other”: it’s the same object that’s just being referenced by two separate variables.


    To answer the follow-up questions from the comment:

    How do I need to imagine it that an int variable is a value type and string is a reference type? I mean, so the int variable directly contains the number and the string variable is just like a pointer to a storage location of the string object?

    Yes, that’s exactly it. The value of a reference is basically just a pointer to the memory where the object actually is, while the value of a value type is the whole object itself.

    That’s why e.g. having a value type as the parameter to a method means that when the method is called, the whole value type object is copied into the stack for the execution of the method.

    A type being a value type does not mean that its members will all be value types too though. For example, the actually stored value of a string member inside a value type is still a reference to the string object. Similarly, the actual memory for a reference type will contain the actual value for value types, and references to other memory locations for reference types.

    If the parent type always matter more than the objects types, what can I use the type of int and string for?

    There is nothing that matters more than another. An object being a value or a reference type has only implications on how that object is stored. For members of the object, this is evaluated completely separately.

    Is it possible if you just have one class and a bunch of variables to set some of them just as a reference to another variable, for example int variables.

    You cannot have a reference pointer for a value type, like you could have in C, no. But you can have references to fields which allow you to mutate the value of fields that are of a value type. For example:

    class Test
    {
        private int field;
    
        public void ShowExample()
        {
            // set the value
            field = 12;
    
            // call the method and pass *a reference* to the field
            // note the special syntax
            MutateField(ref field);
    
            // the field, which is a value type, was mutated because it was passed as a reference
            Console.WriteLine(field == 4);
        }
    
        private static void MutateField(ref int value)
        {
            value = 4;
        }
    }