Why doesn't the constructor affect the properties in this example
I'm wondering why, when we have p = new Person("TOM", 999);
, calling fred.PrintInfo();
It doesn't change p to TOM and 999, but using p.age = 99; we can change the age of fred and both constructors and properties are public, then, what's here that I'm missing? I don't want to do anything with this code, I just need a 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();
}
}
source to share
fred
points to a specific location in memory:
+------------+
fred ----> | Fred 12 |
+------------+
When calling SendAPersonByValue p
points to the same location:
+------------+
fred ----> | Fred 12 |
+------------+
^
p ---------+
p.age = 99;
now changes the value in memory:
+------------+
fred ----> | Fred 99 |
+------------+
^
p ---------+
whereas it new Person("TOM", 999);
creates a new Person in memory and p = ...
points p
to it:
+------------+
fred ----> | Fred 99 |
+------------+
+------------+
p ----> | TOM 999 |
+------------+
And that's why fred
it still contains Fred, 99
.
Now, if you need to pass fred
as a parameter ref
, p
it will be 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 |
+------------+
source to share
If you want the person's link in the main text to change to a new link, you need to put the ref in the parameter list. Otherwise, the stack has a reference to where it is primarily used. It can change internal properties, but not the link that belongs to the main element that it passed.
source to share
This is because you created a new link. If you want the behavior you expected, you will have to change the SendAPersonByValue method to ref Person p
.
So here's what's going on here:
SendAPersonByValue(fred);
//You are passing the value of fred reference here
...
public static void SendAPersonByValue(Person p)
{
p.age = 99;
//The value of Fred reference is used to populate his age
p = new Person("TOM", 999);
//p is now assigned to a totally new reference.
//Because value 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 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
}
source to share