2013-03-05 54 views
-2

我的問題涉及在C#中使用對象。我想我明白髮生了什麼,但我想明白爲什麼。由於我不會涉及的原因,我想用當前數據(當前狀態)創建對象的臨時副本。所以我想我可以創建一個新對象,將它分配給原始對象,然後更改原始對象。那時我會有兩個不同狀態的物體。但是,發生的事情是複製的對象看起來和第一個完全一樣。下面是一些代碼來說明:爲什麼我的對象是一個指針?

Order o1 = new Order(); 
o1.property1 = "test 1"; 

Order o2 = new Order(); 
o2 = o1; 

o1.property1 = "test 2"; 

但在這段代碼結束,無論O1和O2都property1設置爲「測試2」。我想我意識到所有的對象都只是指針,所以如果你改變它,它會改變另一個,但我不明白爲什麼這是,或者它爲什麼有用。我在這裏錯過了一些基本的東西嗎?另外,完成我想要做什麼的最好方法是什麼?即:存儲對象的狀態,進行更改,然後在必要時恢復。希望這是有道理的。

+0

請參閱http://msdn.microsoft.com/en-us/library/t63sy5hs(v=vs.80).aspx解釋這一點的文檔。 – David 2013-03-05 22:53:37

+1

您需要了解引用類型與值類型。當你將o1分配給o2時,類是引用類型,你實際上將一個引用分配給o1,因此o1和o2都指向內存中的相同位置。這就是C#如何與引用類型(即類)一起工作。 – 2013-03-05 22:58:59

+0

謝謝Stan。關鍵在於賦值o2 = o1只是將引用賦值給對象,而不是賦值給它。 – bardogodspeed 2013-03-05 23:05:02

回答

7

C#中的對象變量是參考(不是指針)到內存中的特定對象。當您聲明

Order o2 = new Order(); 

您正在堆中創建一個新的Order對象,並將該對象的引用分配給您的o2變量。當你然後狀態

o2 = o1; 

你告訴編譯器使o2對o1的引用。此時,對原始o2對象的引用將丟失,並且該對象的內存將在下次垃圾回收掃描期間被刪除。

因此,o1和o2都指向內存中的同一個對象。要將信息從一個對象複製到另一個對象,您需要實現一個過程來實例化新的目標對象,並將所有數據從一個對象複製到另一個對象。有關更多信息,請參閱ICloneable上的MSDN文檔。

2

這是設計。如果你想克隆並保持克隆獨立,我會建議在你的類型上實現一個「克隆」機制。這可以是ICloneable或甚至只是一個構造函數,該構造函數接受一個實例並從中複製值。

1

根據定義,物體是'指針';他們持有參考到您的數據,而不是實際數據本身。你可以爲它賦值類型,但它會給出保存數據的外觀。

如上所述,理解Value types vs. Reference types是關鍵。

4

你所指的是值類型和引用類型之間的差異。顯然你的Order對象是一個引用類型,我會認爲它是一個類。

類是引用類型,意味着它們是「指針」。其中一個原因是性能,因爲每次分配變量時都不希望複製大量數據。

結構是值類型,將在您分配它們時複製到內存中。

你有2個解決方案:

  • 使用使用結構,而不是類
  • 克隆的對象要麼MemberwiseClone如果它是非常簡單的,或者如果你需要執行一個深克隆使用自己的方法。
+2

請不要使用結構,除非您完全確定您瞭解引用和值類型之間的差異。 – 2013-03-05 23:01:44

1

Java沒有除對象引用以外的任何非原始數據類型的概念;因爲幾乎所有可以用對象引用做的事情都涉及到對這個對象引用的對象,即Java中的.運算符。儘管.net具有非原始值類型,但絕大多數.net語言都遵守約定(與C和C++不同,它使用->訪問指向對象的成員,.訪問結構的成員)相同的.運算符用於「解除引用和訪問成員」和「訪問值類型成員」。個人而言,我不喜歡Java的「一切都是對象引用」設計,而.net決定讓值類型和引用類型使用相同的.運算符來表示非常不同的東西並不會有幫助,但它就是這樣。

2

關於你的問題

會是什麼來完成我想要做的最好的方法?它是: 存儲中的對象的狀態,進行更改,然後恢復如有必要

一個簡單的方法是簡單地序列化對象,例如使用XMLSerializer。然後,如果你想拋棄你的修改,只需反序列化原始對象,並用原始版本替換修改後的對象。

2

使用結構來完成您的任務,類是引用類型,結構是值類型。 類存儲在內存堆 結構存儲在堆棧上。 欲瞭解更多信息搜索結構與類和學習差異

相關問題