为什么在将对象设置为其他实例时,只更新本地引用

时间:2012-05-03 11:37:14

标签: c# object pointers

当我这样做时:

var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;

然后:

foo = new Customer("Dave");

仅更新foo,其他人仍为“彼得”。

但是当我这样做时:

foo.Name = "Dave";

然后更新所有对象。这是为什么?

5 个答案:

答案 0 :(得分:1)

当它引用类型时,变量(在您的示例中为foo)仅存储引用。为变量赋值时,只更改此变量,而不是之前引用的对象。

class Customer
{
    public Customer(string name)
    {
        Name = name;
    }
    public string Name { get; set; }

    public static Customer Current { get; set; }
}

您期望的行为可以使用上面的代码完成。如果将Customer.Current设置为某个值,那么要求Customer.Current的每个代码都将获得先前设置的Customer。但是,静态变量通常不是很好的设计选择,并且带有一系列问题(可测试性,线程问题等)。

答案 1 :(得分:1)

在这里,您将新客户对象分配给foo。这三行表示foo,sth和foo2指向Customer(Peter):

var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;

但是在这里,你说foo应该指向另一个客户(Dave)。其他“指针”不会改变,因为它们与Dave无关:

foo = new Customer("Dave");

但是在这里你说Peter对象中的Name属性应该改为Dave。你使用foo来获取实际的对象,然后改变对象本身的某些东西:

foo.Name = "Dave";

sth和foo2仍然指向您更改的对象。他们的参考文献没有改变;对象本身有一个内部的变化。 ......和foo2并不关心这一点,他们唯一的工作就是指出他们所说的一切。

答案 2 :(得分:1)

如果你真的想要这种引用链接(非常奇怪的情况,顺便说一句),你可以创建一个新类,如:

public class CustomerRef
{
     public Customer Obj { get; set; }
}

因此,您的示例代码将变为:

var foo = new CustomerRef(new Customer("Peter"));  
var sth = foo;  
var foo2 = foo; 

然后

foo.Obj = new Customer("Dave"); 

所有变量都会继续引用新对象。如果您想更改名称,请执行以下操作:

foo.Obj.Name = "Dave"; 

答案 3 :(得分:0)

引用是一个变量,其值是对象的引用。当您将引用更改为指向其他对象时,该值是新引用。因此,对前一个对象的引用保持不变。

答案 4 :(得分:0)

引用只是堆中对象的地址(类是引用类型)。让我们看看当你这样做时会发生什么:

var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;

想象一下堆是美国。当你创建新客户彼得时,他有一些地址,如33132 Miami Florida。考虑地址簿中的记录等变量。当你把彼得分配给某个变量时,它实际上只存储了彼得的地址,而不是彼得的身体(在地址簿中保留人体的一点点奇怪)。在您的示例中,地址簿中有三行:

var foo = [33132 Miami Florida] // Peter's address
var sth = [33132 Miami Florida] // copy address from foo record
var foo2 = [33132 Miami Florida]

然后您创建新客户Dave,其中包含New Your:

foo = new Customer("Dave");

删除地址簿中foo行上的内容。并在那里放下戴夫的地址:

 var foo = [10012 New York, NY] // this is address of Dave!
 var sth = [33132 Miami Florida] // other records in book has not changed
 var foo2 = [33132 Miami Florida]

但是当你使用对象的地址向他发送消息时,这是不同的故事。

foo.Name = "Dave";

这向居住在迈阿密的彼得发送信息,他应该将自己的名字改为戴夫。彼得的地址没有改变。所以其他记录也有Peter的地址。改变的是彼得!只有一个彼得。你只需要在几个记录中保存他的地址。

如果你从sth记录中取出彼得的地址,并向他发送消息'嘿,有人在佛罗里达州迈阿密33132地址,你的名字是什么?',那么彼得将把你的新名字发给你:

string name = sth.Name;

BTW垃圾收集器不会只杀死那些地址簿中存在地址的人。