为什么构造函数不会影响此示例中的属性

时间:2012-03-29 13:53:54

标签: c#

我想知道为什么当我们通过调用p = new Person("TOM", 999); fred.PrintInfo();时 它不会将p改为TOM和999,而是使用p.age = 99;我们可以很好地改变fred的年龄,构造函数和属性都是公共的,那么我在这里缺少什么?我不想对这段代码做任何事我只是想要原因。

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();
    }
}

5 个答案:

答案 0 :(得分:20)

fred指向内存中的某个特定位置:

           +------------+
fred ----> | Fred    12 |
           +------------+

调用SendAPersonByValue后,p指向同一位置:

           +------------+
fred ----> | Fred    12 |
           +------------+
              ^
  p  ---------+

p.age = 99;现在更改了内存中的值:

           +------------+
fred ----> | Fred    99 |
           +------------+
              ^
  p  ---------+

new Person("TOM", 999);在内存中创建了一个 new Person,p = ...使p指向它:

           +------------+
fred ----> | Fred    99 |
           +------------+

           +------------+
  p  ----> | TOM    999 |
           +------------+

这正是fred仍包含Fred, 99的原因。


现在,如果您将fred作为ref parameter传递,p将成为fred别名

             +------------+
fred/p ----> | Fred    12 |
             +------------+

p.age = 99之后:

             +------------+
fred/p ----> | Fred    99 |
             +------------+

p = new Person("TOM", 999);之后:

             +------------+
             | Fred    99 |    (will be garbage collected eventually)
             +------------+

             +------------+
fred/p ----> | TOM    999 |
             +------------+

答案 1 :(得分:4)

因为只是Person p的参考传递而不是参考的参考。

您需要执行此操作才能通过引用传递Person。:

public static void SendAPersonByValue(ref Person p)
{
    p.age = 99;

    p = new Person("TOM", 999);
}

答案 2 :(得分:2)

如果您希望main中的人员引用更改为新引用,则必须将ref放入参数列表中。否则,堆栈具有对主要使用的位置的引用。它可以更改内部属性,但不能更改引用,而引用主要保存到它传入的项目。

答案 3 :(得分:1)

这是因为您创建了一个新参考。如果您想要您期望的行为,则必须将SendAPersonByValue方法更改为ref Person p

所以,这里发生的是:

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
}

将ref添加到方法签名时会发生什么:

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

答案 4 :(得分:1)

在方法SendAPersonByValue(Person p)中分配变量p时,只能在本地分配。它不会在主方法中更改fred

您可以在主方法中返回修改后的人并替换fred,也可以使用ref关键字。