In C#, there are two catgories of objects: Value-Types and Reference-Types.
Value-Types are struct
s and enum
s, such as int
(System.Int32
). These types always copied when they're passed. If you change an int
in a method, the variable inside the caller won't change.
You are talking about reference types - classes, arrays and interfaces, basically.
In reference types, such as string
(System.String
), there are two sections: the object, and the pointer. For example, let's see your Employee
. Suppose I declared a variable named e1
of type Employee
, and assigned to it's name "abc"
:
Employee e1 = new Employee { Name = "abc" };
Now, there is an employee object in the memory (the heap, because reference types almost always are allocated in the heap, expect stackalloc
), which contains Name="abc"
. There is also (in the stack) a pointer to this object. Let's suppose we have this memory image:
0x123 - An employee object 0x45F - the variable `e1` - pointer to the employee
|-------------------------| |------------------|
| Name = "abc" | | 0x123 |
|-------------------------| |------------------|
When you pass it without ref
, the value of e1
- 0x123
is copied, but the employee isn't copied! So, if you change its name, the original employee will be changed! But if you change the pointer nothing will happen, since the pointer e1
is just copied!
When you pass with ref
, the address of the pointer is copied - 0x45F
. So, if you change the parameter, it will change e1
, since it was not copied, but its address.
Edit:
If I assign a reference type variable to an another variable, for example:
var e1 = new Employee { Name = "abc" };
Employee e2 = employee;
then, e2
is the same as e1
- it'a also a pointer, which points to the same address. If we takes the prevoius memory image, now there is in the address 0x4AC
a variable named e2
, contains also 0x123
, the address of the object. So, if we'll change e2.Name
:
e2.Name = "new";
then, e1.Name
is now "new"
, too.
Last important fact about reference types, is that comparing (==
) reference types (I'm talking when there is not an overloaded operator ==
), won't check if they contains the same values, but if they points to the same object. Let's see an example:
var e1 = new Employee { Name = "abc" };
Employee e2 = e1;
var e3 = new Employee { Name = "abc" };
var e4 = new Employee { Name = "123" };
Console.WriteLine(e1 == e4); // false
Console.WriteLine(e1 == e3); // false, since they don't point to the same object, they just contain the same values
Console.WriteLine(e1 == e2); // true, since they point to the same object
Some comments about strings:
- Althought the class
System.String
is a reference type, it overloads operator ==()
, so comparing two strings will give a correct result.
- The compiler usually optimize strings, so if
string s1 = "abc";
and string s2 = "abc";
, s1
and s2
can point to the same address (for memory saving). It's possible because strings are immutable - if, for example, you call Replace()
on a string, it'll create a new string. So you shouldn't know about this (but it's important if you write unsafe code).