One of the most common mistakes that C# learners make relates to reference and value types. The mistake is because the reference type is passed by reference, which holds the complete object and value type by value. We will try to clarify this issue in this post.
How it all begins.
One of the first topics we come across when learning C# is the topic that shows how Stack and Heap work, grouping types according to these memory models. At the heart of the topic is to separate variable types into two main categories, showing how variables behave on the Stack and Heap.
Stack and Heap
On the .NET platform, variables can be stored on the Stack and Heap. Valuable types (int, uint, long, ulong, short, ushort, byte, sbyte, char, bool, decimal, double, float) are all stored according to the Stack memory model. A stack memory area can store a small amount of data, but it is very fast compared to Heap.
ReferenceType (types are mainly stored in the Heap memory area. These include class, interface, delegate, array, object, and string. Although these objects are stored on the Heap, their address is still stored on the Stack! Although the Heap memory space can handle more extensive data than the Stack, it lags behind it in terms of speed.
class Employee {
public int Id {
get;
set;
}
public string Name {
get;
set;
}
}
class Program {
static void Main(string[] args) {
Employee employee = new Employee {
Id = 1,
Name = "Jonathan"
};
}
}
If we describe the above code in memory, such an image appears.
As you can see from the picture, space is allocated to an object in the Heap memory area when an object is created.
Axiom of passing types as arguments.
According to the name of the reference, type is often an illusion that if it is a value type, then when it is passed as an argument to any method, the value is passed; if it is a reference type, then it is passed according to the link, that is, according to the address.
As you can see from the picture, objects of linked types fall into the Heap memory area, but their addresses "live" in Stack. If we give a reference type as an argument to a method, that type is changed, giving us the illusion of passing by address.
static void Main(string[] args) {
Employee employee = new Employee {
Id = 1,
Name = "Jonathan"
};
WriteLine($ "Before : {employee.Name}");
ChangeEmployeeName(employee);
WriteLine($ "After : {employee.Name}");
ReadLine();
}
static void ChangeEmployeeName(Employee employee) {
employee.Name = "Simon";
}
As you can see from the picture, if we give a reference type to a method, that type is changed. Many people start from this idea and conclude that reference type is passed by link.
The problem is that the address of the reference type falls on the Stack, and when a method calls the linked type as an argument, it sends the ADDRESS AS THE VALUE because it's the only address available on the Stack.
In .NET, all types, be they stack or heap types, are all passed by value!!
Trying to convince you…
Question 1
If the reference type is passed by reference, why does this code not produce the expected result?
If the concept of transmission by address were correct, the word "Simon" would appear on the screen. When the method is invoked, the old memory space is left unchanged, and the new memory space is assigned to the variable. The GC will clean up that memory after the method has finished working. And we check whether the price has changed by referring to the old memory.
Question 2
If the reference type is passed by reference, why is the following code passed?
static void Main(string[] args) {
Employee employee = new Employee {
Id = 1,
Name = "Jonathan"
};
WriteLine($ "Before : {employee.Name}");
ChangeEmployeeName(ref employee);
WriteLine($ "After : {employee.Name}");
ReadLine();
}
//the real "passing by reference"
static void ChangeEmployeeName(ref Employee employee) {
employee = new Employee {
Name = "Simon"
};
}
We will use the ref and out keywords if we need to pass types by address.