Reputation: 143
I am wondering why when we have p = new Person("TOM", 999);
by calling fred.PrintInfo();
It doesn't change the p to TOM and 999 but by using p.age = 99; we can change the fred's age well the both constructor and properties are public then what is here that I am missing? I don't want to do anything with this code I just want the reason.
using System;
class Person
{
public string fullName;
public int age;
public Person(string n, int a)
{
fullName = n;
age = a;
}
public void PrintInfo()
{
Console.WriteLine("{0} is {1} years old", fullName, age);
}
}
class MainClass
{
public static void SendAPersonByValue(Person p)
{
p.age = 99;
p = new Person("TOM", 999);
}
public static void Main()
{
Person fred = new Person("Fred", 12);
fred.PrintInfo();
SendAPersonByValue(fred);
fred.PrintInfo();
}
}
Upvotes: 3
Views: 135
Reputation: 172448
fred
points to some particular location in memory:
+------------+
fred ----> | Fred 12 |
+------------+
Upon calling SendAPersonByValue, p
points to that same location:
+------------+
fred ----> | Fred 12 |
+------------+
^
p ---------+
p.age = 99;
now changes the value in memory:
+------------+
fred ----> | Fred 99 |
+------------+
^
p ---------+
whereas new Person("TOM", 999);
creates a new Person in memory, and p = ...
makes p
point to it:
+------------+
fred ----> | Fred 99 |
+------------+
+------------+
p ----> | TOM 999 |
+------------+
And this is exactly why fred
still contains Fred, 99
.
Now, if you were to pass fred
as a ref
parameter, p
would become an alias for fred
:
+------------+
fred/p ----> | Fred 12 |
+------------+
After p.age = 99
:
+------------+
fred/p ----> | Fred 99 |
+------------+
After p = new Person("TOM", 999);
:
+------------+
| Fred 99 | (will be garbage collected eventually)
+------------+
+------------+
fred/p ----> | TOM 999 |
+------------+
Upvotes: 20
Reputation: 67135
This is because you have created a new reference. If you want the behavior that you expected you will have to change your SendAPersonByValue method to be ref Person p
.
So, what is happening here is this:
SendAPersonByValue(fred);
//You are passing the value of fred's reference here
...
public static void SendAPersonByValue(Person p)
{
p.age = 99;
//The value of Fred's reference is used to populate his age
p = new Person("TOM", 999);
//p is now assigned to a totally new reference.
//Because value's are immutable, fred remains
//However, p is now pointing to a different reference value
}
What happens when you add ref to your method signature:
SendAPersonByValue(ref fred);
//A reference (pointer) to Fred's reference value is passed
...
public static void SendAPersonByValue(Person p)
{
p.age = 99;
//The pointer of the reference of Fred is used to populate his age
//Ultimately, this is the same as above because the both end up at Fred
p = new Person("TOM", 999);
//The reference value of p (fred) is now the new reference
//since it was just a pointer to the reference value
}
Here is a good article on the subject of values and references
Upvotes: 1
Reputation: 11111
When you assign the variable p in the method SendAPersonByValue(Person p)
you only assign it locally. It does not change fred
in your main method.
You can return the modified person and replace fred in the main method, or you can use the ref
keyword.
Upvotes: 1
Reputation: 31721
If you want the person reference in the main to change to a new reference then one has to put the ref in the parameter list. Otherwise the stack has a reference to a location which main uses. It can change internal properties, but not the reference which main holds to the item it passed in.
Upvotes: 2
Reputation: 81700
Because just the reference of the Person p
is passed not reference of the reference.
You need to do this in order to pass the Person by reference.:
public static void SendAPersonByValue(ref Person p)
{
p.age = 99;
p = new Person("TOM", 999);
}
Upvotes: 4