1. 程式人生 > >C# List 賦值(一) --引用類型的賦值和復制

C# List 賦值(一) --引用類型的賦值和復制

地址 修改 引用 進行 urn ont pre 詳細 理論

最近項目維護中遇到一個問題,確切的說應該是兩個月前的問題也是因為這裏引起的,可惜當時困於業務不熟悉,也沒有更多時間允許查詢根源,導致再次引發了新的問題!!!

問題場景:基礎數據存於List類型的BOMs中,計算過程是對List類型的normalBoms和configBoms變量傳值後,normalBoms和configBoms進行計算,發現

對configBoms的操作會修改基礎數據BOMs中的值!!!

起初就考慮到是因為List類型是引用類型,所以傳值會修改原值,但是normalBoms的值沒有同步被修改,所以詳細比較兩個變量的傳值邏輯:

 1             static List<int
> BOMs = new List<int>(); 2 static void Main(string[] args) 3 { 4 for (int i = 0; i < 10; i++) 5 { 6 BOMs.Add(i); 7 } 8 9 List<int> normalBoms = null; 10 List<int> configBoms = null
; 11 12 normalBoms = GetNormalBoms(); 13 configBoms = GetConfigBoms(); 14 15 configBoms[9] = 19; 16 17 } 18 static List<int> GetNormalBoms() 19 { 20 List<int> boms = new List<int>(); 21 //... 22 foreach
(int bom in boms) 23 { 24 //... 25 boms.Add(bom); 26 } 27 //...... 28 return boms; 29 } 30 31 static List<int> GetConfigBoms() 32 { 33 List<int> boms = null; 34 //...... 35 boms = BOMs; 36 //...... 37 return boms; 38 }

註意:GetNormalBoms()方法中行22和方法GetConfigBoms()方法中行35的差異,所以猜測(因為沒有認真考慮)是沒有進行new操作(new會分配新的內存),最終導致configBoms還是只想BOMs的同一個內存,即發放返回了一個引用,後續對configBoms的操作也會影響BOMs,作出相應修改:

行10List<int> configBoms = null; 修改為 List<int> configBoms = new List<int>(); ,(分配了內存,configBoms是指向新的內存的)

最終運行,發現後續對configBoms的操作還是會影響BOMs,更加詳細的思考為什麽???

這裏就開始認真回想之前對引用類型的理解,因為常有查看值類型和引用類型的區別,現在是理論和實踐的結合了:

首先,理解引用類型的變量存儲的是內存的地址(對象的引用),即對象的數據在托管堆中,變量中的引用在棧上(借鑒:http://www.cnblogs.com/anding/p/5229756.html)

其次,引用類型的變量賦值傳遞的是對象的應用,也就是變量賦值的是內存的地址,所以賦值後多個變量指向了同一個對象實例

基於以上兩點,代碼中問題不難解釋了:雖然configBoms通過new操作分配了新的內存(此時新分配的內存記為mom1,原來BOMs指向的內存mom0),但是後續的賦值操作configBoms=GetConfigBoms()中沒有修改內存指向,所以賦值操作是變量configBoms的值,即configBoms中的地址不在指向mom1,而是指向了mom0,此時的configBoms是mom0存儲的對象實例的一個引用,和BOMs等同,所以修改configBoms會影響BOMs。(:內存mom1並沒有消失,只是configBoms不在指向mom1,也不能通過configBoms修改mom1的內容)

但是反觀方法GetNormalBoms()方法,方法中先通過new分配了行的內存(記為mom2),然後為新的變臉賦值是通過Add方法,是在新的內存mom2中增加數據,變量中的地址沒有變,所以normalBoms變量還是指向mom2的,與configBoms和BOMs不同。

了解了原理,那麽解決我的問題的方法就是:在給configBoms傳值時,不能只修改變量值,而是要分配新內存,數據要賦值進新內存中

List的復制(借鑒:https://blog.csdn.net/chrean/article/details/5686998)

因為考慮到實際項目中,不是循環都合適,同時現有代碼結構不易修改,不通過類似GetNormalBoms()的方法給configBoms賦值,通過new List<int>(BOMs)進行賦值,即:

行13修改為 configBoms = new List<int>(GetConfigBoms());

問題最終是解決了。所以學以致用,細致入微,真的是很基礎的內容,以前只知道概念,現在真正才是開始將學習的知識運用到實踐中來。

C# List 賦值(一) --引用類型的賦值和復制