Reference types vs Value types

Both value types and reference types are used to represent data, but they behave differently in terms of memory allocation, assignment, and passing to methods.

Memory Allocation:
Value Types:
Value types are stored directly in memory where they are declared. They typically reside on the stack. Examples of value types include simple types like int, float, char, and structs.

Reference Types:
Reference types are stored in memory on the heap.
When you declare a reference type variable, the variable itself stores a reference (or memory address) to the actual data on the heap.
Examples of reference types include classes, arrays, and interfaces.

Assignment:
Value Types:
When you assign a value type variable to another variable, a copy of the value is created.
Modifications to one variable do not affect the other.

Reference Types:
When you assign a reference type variable to another variable, you're actually copying the reference to the same underlying object in memory.
Both variables will refer to the same object, so changes made through one variable will be reflected when accessing the object through the other variable.

Passing to Methods:
Value Types:
When you pass a value type variable to a method, a copy of the variable's value is passed.
Any modifications made to the parameter inside the method do not affect the original variable.

Reference Types:
When you pass a reference type variable to a method, you're passing the reference to the same object in memory.
Therefore, changes made to the object inside the method will affect the object outside the method.

Nullability:
Value Types:
Value types cannot be null unless they are nullable value types, which are declared using the ? modifier (e.g., int?, float?).
Nullable value types can represent the value of the underlying type or a null value.

Reference Types:
Reference types can be null by default. If a reference type variable is not initialized, it will point to null, indicating that it does not reference any object in memory.