当我这样做时:
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
然后:
foo = new Customer("Dave");
仅更新foo
,其他人仍为“彼得”。
但是当我这样做时:
foo.Name = "Dave";
然后更新所有对象。这是为什么?
答案 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垃圾收集器不会只杀死那些地址簿中存在地址的人。