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,作出相应修改:

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

最终运行,发现后续对configBoms的操作还是会影响BOMs,更加详细的思考为什么???

这里就开始认真回想之前对引用类型的理解,因为常有查看值类型和引用类型的区别,现在是理论和实践的结合了:

首先,理解引用类型的变量存储的是内存的地址(对象的引用),即对象的数据在托管堆中,变量中的引用在栈上(借鉴:http://www.cnblogs.com/anding/p/5229756.html

其次,引用类型的变量赋值传递的是对象的应用,也就是变量赋值的是内存的地址,所以赋值后多个变量指向了同一个对象实例

扫描二维码关注公众号,回复: 2566891 查看本文章

基于以上两点,代码中问题不难解释了:虽然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()); 

问题最终是解决了。所以学以致用,细致入微,真的是很基础的内容,以前只知道概念,现在真正才是开始将学习的知识运用到实践中来。

猜你喜欢

转载自www.cnblogs.com/jie0602/p/9427041.html