當我這樣做:爲什麼它是一個對象設置爲不同的實例時,只有本地參考更新
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
然後:
foo = new Customer("Dave");
僅foo
更新和其他人仍然是「彼得」。
但是當我做:
foo.Name = "Dave";
那麼所有的對象都更新。爲什麼是這樣?
當我這樣做:爲什麼它是一個對象設置爲不同的實例時,只有本地參考更新
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
然後:
foo = new Customer("Dave");
僅foo
更新和其他人仍然是「彼得」。
但是當我做:
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。但是,靜態變量通常不是很好的設計選擇,並伴隨着它們的一系列問題(可測試性,線程問題等)。
任何方式來改變所有的引用沒有太多麻煩? – user1151923
可能有很多變量引用同一個對象。如果使用其中一個引用更改對象,則可以從指向該對象的每個變量中看到更改。 – empi
是的,我明白,但我想切換一個完全不同的實例的對象,以便所有的引用得到更新,並'看'新的對象 – user1151923
引用是一個變量,其值是對該對象的引用。當您將參考更改爲指向不同的對象時,該值是新的參考。因此,對前一個對象的引用保持不變。
在此處爲foo分配新客戶對象。這三行意味着富,某事,和foo2的指向客戶(彼得):
var foo = new Customer("Peter");
var sth = foo;
var foo2 = foo;
但在這裏,你是說,FOO應指向另一個客戶(戴維)。其他的「指針」不改變,因爲他們什麼都沒有做與戴夫:
foo = new Customer("Dave");
但在這裏,你是說,在彼得對象的名稱屬性應該改變戴夫。您正在使用FOO獲得實際的對象,然後改變物體本身的東西:
foo.Name = "Dave";
......而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;
想象一下,堆是美國。當你創造新的客戶彼得時,他有一些像佛羅里達州邁阿密33132的地址。考慮地址簿中的記錄等變量。當你將Peter分配給某個變量時,它實際上只存儲彼得的地址,而不是彼得的身體(它在通訊簿中保持人體的奇怪)。在您的例子有三個行地址簿:
var foo = [33132 Miami Florida] // Peter's address
var sth = [33132 Miami Florida] // copy address from foo record
var foo2 = [33132 Miami Florida]
然後創建新的客戶戴夫其住在新的你:
foo = new Customer("Dave");
您刪除什麼是你的地址簿寫上線foo
。並放下Dave的地址:
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
記錄彼得的地址,並給他發信息「嘿,有人在地址33132佛羅里達州邁阿密,你叫什麼名字?」,然後彼得會送你他的新名字:
string name = sth.Name;
順便說一句垃圾收集器不殺死只有那些人,哪個地址存在於地址簿中。
你是否起訴foo.Name更改sth.Name和foo2.Name?它應該只改變foo.Name –
最初foo,sth和foo2都指向同一個對象,因此該對象的Name屬性對於所有三個引用都會顯示更改。一旦將不同的對象(「Dave」)分配給foo,則名稱更改不會再影響它。 –