C# List 賦值(一) --引用類型的賦值和復制
最近項目維護中遇到一個問題,確切的說應該是兩個月前的問題也是因為這裏引起的,可惜當時困於業務不熟悉,也沒有更多時間允許查詢根源,導致再次引發了新的問題!!!
問題場景:基礎數據存於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,作出相應修改:
行10的 List<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 賦值(一) --引用類型的賦值和復制