Negin Nicki
Negin Nicki

Reputation: 143

why a constructor doesn't affect the properties in this example

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

Answers (5)

Heinzi
Heinzi

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

Justin Pihony
Justin Pihony

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

Anders Forsgren
Anders Forsgren

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

ΩmegaMan
ΩmegaMan

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

Aliostad
Aliostad

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

Related Questions