当我做:
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
进而:
foo = new Customer("Dave");
onlyfoo
已更新,其他仍将是“Peter”。
但是当我这样做时:
foo.Name = "Dave";
然后更新所有对象。为什么是这样?
当涉及到引用类型时,变量(在您的示例中为 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。但是,静态变量通常不是很好的设计选择,并且会带来一系列问题(可测试性、线程问题等)。
在这里,您将一个新的客户对象分配给 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 不在乎,他们唯一的工作就是指出他们被告知的任何内容。
如果您真的想要这种引用链接(非常奇怪的情况,顺便说一句),您可以创建一个新类,例如:
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";
引用是一个变量,其值是对对象的引用。当您将引用更改为指向不同的对象时,该值是一个新的引用。因此,对前一个对象的引用保持不变。
引用只是堆中对象的地址(类是引用类型)。让我们看看当你这样做时会发生什么:
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
想象堆是美国。当您创建新客户 Peter 时,他有一些地址,例如 33132 Miami Florida。考虑变量,例如地址簿中的记录。当您将 Peter 分配给某个变量时,它实际上只存储了 Peter 的地址,而不是 Peter 的身体(将人员的身体保存在地址簿中有点奇怪)。在您的示例中,地址簿中有三行:
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";
这向住在迈阿密的彼得发送了一条消息,他应该将自己的名字改为戴夫。彼得的地址没有改变。所以其他记录也包含彼得的地址。改变的是彼得!而且只有一个彼得。您只需将他的地址保存在几份记录中。
如果您从sth
记录中获取 Peter 的地址,并向他发送消息“嘿,有人在地址 33132 Miami Florida,你叫什么名字?”,那么 Peter 将向您发送他的新名字:
string name = sth.Name;
顺便说一句,垃圾收集器不会只杀死地址簿中存在的那些人。